diff --git a/.github/workflows/build_test_deploy.yml b/.github/workflows/build_test_deploy.yml index 0a2063790d..d72d4b90ef 100644 --- a/.github/workflows/build_test_deploy.yml +++ b/.github/workflows/build_test_deploy.yml @@ -655,7 +655,7 @@ jobs: name: next-swc-test-binary path: packages/next-swc/native - - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-jammy /bin/bash -c "cd /work && NODE_VERSION=${{ env.NODE_LTS_VERSION }} ./scripts/setup-node.sh && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_SWC_DEV_BIN=1 NEXT_TEST_JOB=1 NEXT_TEST_CNA=1 xvfb-run node run-tests.js test/integration/create-next-app/index.test.ts test/integration/create-next-app/templates.test.ts >> /proc/1/fd/1" + - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-jammy /bin/bash -c "cd /work && NODE_VERSION=${{ env.NODE_LTS_VERSION }} ./scripts/setup-node.sh && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_SWC_DEV_BIN=1 NEXT_TEST_JOB=1 NEXT_TEST_CNA=1 xvfb-run node run-tests.js test/integration/create-next-app/*.test.ts >> /proc/1/fd/1" if: ${{ needs.build.outputs.docsChange == 'nope' }} - name: Upload test trace diff --git a/packages/next-swc/crates/next-dev-tests/tests-manifest.js b/packages/next-swc/crates/next-dev-tests/tests-manifest.js index ee264173de..25eae38737 100644 --- a/packages/next-swc/crates/next-dev-tests/tests-manifest.js +++ b/packages/next-swc/crates/next-dev-tests/tests-manifest.js @@ -1,478 +1,269 @@ -// Tests that are currently disabled with Turbopack in CI. -// Any tests not listed in here are assumed to be enabled. -const disabledTests = [ - // these are build specific - 'test/integration/auto-export-error-bail/test/index.test.js', - 'test/integration/auto-export-query-error/test/index.test.js', - - // these are build specific - 'test/integration/build-output/test/index.test.js', - 'test/integration/build-trace-extra-entries-turbo/test/index.test.js', - 'test/integration/build-trace-extra-entries/test/index.test.js', - 'test/integration/build-warnings/test/index.test.js', - - // next build specific - 'test/integration/config-schema-check/test/index.test.js', - 'test/integration/config-syntax-error/test/index.test.js', - 'test/integration/config-validation/test/index.test.ts', - 'test/integration/conflicting-ssg-paths/test/index.test.js', - - // these are already tested against turbopack explicitly in the suite - 'test/integration/create-next-app/index.test.ts', - 'test/integration/create-next-app/templates.test.ts', - - // next build specific - 'test/integration/critical-css/test/index.test.js', - - // custom-server isn't compatible with turbopack why is it here? - 'test/integration/custom-server-types/test/index.test.js', - - // Clean dist dir is a production only test should it be here? - 'test/integration/clean-distdir/test/index.test.js', - - // this is next build specific why is it here? - 'test/integration/dist-dir/test/index.test.js', - - // these are next build specific - 'test/integration/export-404/test/index.test.js', - 'test/integration/export-default-map/test/index.test.js', - 'test/integration/export-dynamic-pages/test/index.test.js', - 'test/integration/export-fallback-true-error/test/index.test.js', - 'test/integration/export-getInitialProps-warn/test/index.test.js', - 'test/integration/export-image-default/test/index.test.js', - 'test/integration/export-image-loader-legacy/test/index.test.js', - 'test/integration/export-image-loader/test/index.test.js', - 'test/integration/export-index-not-found-gsp/test/index.test.ts', - 'test/integration/export-intent/test/index.test.js', - 'test/integration/export-no-build/test/index.test.js', - 'test/integration/export-progress-status-message/test/index.test.js', - 'test/integration/export-subfolders/test/index.test.js', - - // build specific - 'test/integration/middleware-build-errors/test/index.test.js', - 'test/integration/webpack-require-hook/test/index.test.js', - // this is next build and next export specific - 'test/integration/with-electron/test/index.test.js', - 'test/e2e/test-template/{{ toFileName name }}/{{ toFileName name }}.test.ts', - - 'test/development/acceptance-app/app-hmr-changes.test.ts', - 'test/development/acceptance-app/component-stack.test.ts', - 'test/development/acceptance-app/editor-links.test.ts', - 'test/development/acceptance-app/error-message-url.test.ts', - 'test/development/acceptance-app/error-recovery.test.ts', - 'test/development/acceptance-app/hydration-error.test.ts', - 'test/development/acceptance-app/invalid-imports.test.ts', - 'test/development/acceptance-app/ReactRefresh.test.ts', - 'test/development/acceptance-app/ReactRefreshLogBox-builtins.test.ts', - 'test/development/acceptance-app/ReactRefreshLogBox-scss.test.ts', - 'test/development/acceptance-app/ReactRefreshLogBox.test.ts', - 'test/development/acceptance-app/ReactRefreshModule.test.ts', - 'test/development/acceptance-app/ReactRefreshRegression.test.ts', - 'test/development/acceptance-app/rsc-build-errors.test.ts', - 'test/development/acceptance-app/server-components.test.ts', - 'test/development/acceptance-app/version-staleness.test.ts', - 'test/development/acceptance/component-stack.test.ts', - 'test/development/acceptance/error-recovery.test.ts', - 'test/development/acceptance/hydration-error.test.ts', - 'test/development/acceptance/ReactRefreshLogBox-app-doc.test.ts', - 'test/development/acceptance/ReactRefreshLogBox-builtins.test.ts', - 'test/development/acceptance/ReactRefreshLogBox.test.ts', - 'test/development/acceptance/ReactRefreshModule.test.ts', - 'test/development/acceptance/ReactRefreshRegression.test.ts', - 'test/development/acceptance/ReactRefreshRequire.test.ts', - 'test/development/acceptance/server-component-compiler-errors-in-pages.test.ts', - 'test/development/api-route-errors/index.test.ts', - 'test/development/app-render-error-log/app-render-error-log.test.ts', - 'test/development/basic/gssp-ssr-change-reloading/test/index.test.ts', - 'test/development/basic/hmr.test.ts', - 'test/development/basic/misc.test.ts', - 'test/development/basic/next-dynamic.test.ts', - 'test/development/basic/node-builtins.test.ts', - 'test/development/basic/project-directory-rename.test.ts', - 'test/development/basic/styled-components.test.ts', - 'test/development/client-dev-overlay/index.test.ts', - 'test/development/correct-tsconfig-defaults/index.test.ts', - 'test/development/gssp-notfound/index.test.ts', - 'test/development/next-font/build-errors.test.ts', - 'test/development/next-font/deprecated-package.test.ts', - 'test/development/next-font/font-loader-in-document-error.test.ts', - - // below test times out +// Tests that are currently enabled with Turbopack in CI. +// Only tests that are actively testing against Turbopack should +// be enabled here +const enabledTests = [ + 'test/development/acceptance-app/ReactRefreshLogBoxMisc.test.ts', + 'test/development/acceptance-app/ReactRefreshRequire.test.ts', + 'test/development/acceptance-app/dynamic-error.test.ts', + // 'test/development/acceptance/ReactRefresh.test.ts', + 'test/development/acceptance/ReactRefreshLogBox-scss.test.ts', + 'test/development/acceptance/ReactRefreshLogBoxMisc.test.ts', + 'test/development/api-cors-with-rewrite/index.test.ts', + 'test/development/app-dir/multiple-compiles-single-route/multiple-compiles-single-route.test.ts', + 'test/development/app-hmr/hmr.test.ts', + 'test/development/basic/define-class-fields.test.ts', + 'test/development/basic/emotion-swc.test.ts', + 'test/development/basic/legacy-decorators.test.ts', + 'test/development/basic/styled-components-disabled.test.ts', + 'test/development/basic/tailwind-jit.test.ts', + 'test/development/basic/theme-ui.test.ts', + 'test/development/dotenv-default-expansion/index.test.ts', + 'test/development/jsconfig-path-reloading/index.test.ts', + 'test/development/middleware-warnings/index.test.ts', + 'test/development/project-directory-with-styled-jsx-suffix/index.test.ts', 'test/development/repeated-dev-edits/repeated-dev-edits.test.ts', - - 'test/development/watch-config-file/index.test.ts', - 'test/development/webpack-issuer-deprecation-warning/index.test.ts', - 'test/e2e/404-page-router/index.test.ts', - 'test/e2e/app-dir-legacy-edge-runtime-config/index.test.ts', - 'test/e2e/app-dir/actions/app-action.test.ts', - 'test/e2e/app-dir/app-a11y/index.test.ts', - 'test/e2e/app-dir/app-basepath/index.test.ts', - 'test/e2e/app-dir/app-css/index.test.ts', - 'test/e2e/app-dir/app-edge/app-edge.test.ts', - 'test/e2e/app-dir/app-middleware/app-middleware.test.ts', - 'test/e2e/app-dir/app-rendering/rendering.test.ts', - 'test/e2e/app-dir/app-routes-trailing-slash/app-routes-trailing-slash.test.ts', - 'test/e2e/app-dir/app-routes/app-custom-routes.test.ts', - 'test/e2e/app-dir/app-static/app-static-custom-handler.test.ts', - 'test/e2e/app-dir/app-static/app-static.test.ts', - 'test/e2e/app-dir/app/index.test.ts', - 'test/e2e/app-dir/create-root-layout/create-root-layout.test.ts', - 'test/e2e/app-dir/crypto-globally-available/crypto-globally-available.test.ts', - 'test/e2e/app-dir/draft-mode/draft-mode-edge.test.ts', - 'test/e2e/app-dir/draft-mode/draft-mode-node.test.ts', - 'test/e2e/app-dir/dynamic-href/dynamic-href.test.ts', - 'test/e2e/app-dir/edge-runtime-node-compatibility/edge-runtime-node-compatibility.test.ts', - 'test/e2e/app-dir/error-boundary-and-not-found-linking/error-boundary-and-not-found-linking.test.ts', - 'test/e2e/app-dir/front-redirect-issue/front-redirect-issue.test.ts', - 'test/e2e/app-dir/hooks/hooks.test.ts', - 'test/e2e/app-dir/i18n-hybrid/i18n-hybrid.test.js', - 'test/e2e/app-dir/interception-middleware-rewrite/interception-middleware-rewrite.test.ts', - 'test/e2e/app-dir/mdx/mdx.test.ts', - 'test/e2e/app-dir/metadata-dynamic-routes/index.test.ts', - 'test/e2e/app-dir/metadata/metadata.test.ts', - 'test/e2e/app-dir/next-font/next-font.test.ts', - 'test/e2e/app-dir/next-image/next-image.test.ts', - 'test/e2e/app-dir/pages-to-app-routing/pages-to-app-routing.test.ts', - 'test/e2e/app-dir/parallel-routes-and-interception/parallel-routes-and-interception.test.ts', - 'test/e2e/app-dir/parallel-routes-not-found/parallel-routes-not-found.test.ts', - 'test/e2e/app-dir/root-layout-redirect/root-layout-redirect.test.ts', - 'test/e2e/app-dir/root-layout/root-layout.test.ts', + 'test/development/tsconfig-path-reloading/index.test.ts', + 'test/development/typescript-auto-install/index.test.ts', + 'test/e2e/app-dir/_allow-underscored-root-directory/_allow-underscored-root-directory.test.ts', + 'test/e2e/app-dir/actions/app-action-export.test.ts', + 'test/e2e/app-dir/app-alias/app-alias.test.ts', + 'test/e2e/app-dir/app-client-cache/client-cache.test.ts', + 'test/e2e/app-dir/app-css-pageextensions/index.test.ts', + 'test/e2e/app-dir/app-external/app-external.test.ts', + 'test/e2e/app-dir/app-prefetch/prefetching.test.ts', + 'test/e2e/app-dir/app-validation/validation.test.ts', + 'test/e2e/app-dir/app/standalone.test.ts', + 'test/e2e/app-dir/app/useReportWebVitals.test.ts', + 'test/e2e/app-dir/app/vercel-speed-insights.test.ts', + 'test/e2e/app-dir/asset-prefix/asset-prefix.test.ts', + 'test/e2e/app-dir/async-component-preload/async-component-preload.test.ts', + 'test/e2e/app-dir/autoscroll-with-css-modules/index.test.ts', + 'test/e2e/app-dir/back-button-download-bug/back-button-download-bug.test.ts', + 'test/e2e/app-dir/dynamic/dynamic.test.ts', + 'test/e2e/app-dir/global-error/global-error.test.ts', + 'test/e2e/app-dir/import/import.test.ts', + 'test/e2e/app-dir/interpolability-with-pages/navigation.test.ts', + 'test/e2e/app-dir/layout-params/layout-params.test.ts', + 'test/e2e/app-dir/metadata-missing-metadata-base/index.test.ts', + 'test/e2e/app-dir/metadata-suspense/index.test.ts', + 'test/e2e/app-dir/navigation/navigation.test.ts', + 'test/e2e/app-dir/not-found/not-found.test.ts', + 'test/e2e/app-dir/rewrites-redirects/rewrites-redirects.test.ts', + 'test/e2e/app-dir/route-page-manifest-bug/route-page-manifest-bug.test.ts', + 'test/e2e/app-dir/router-autoscroll/router-autoscroll.test.ts', + 'test/e2e/app-dir/router-stuck-dynamic-static-segment/router-stuck-dynamic-static-segment.test.ts', 'test/e2e/app-dir/rsc-basic/rsc-basic.test.ts', - 'test/e2e/app-dir/set-cookies/set-cookies.test.ts', - 'test/e2e/app-dir/trailingslash/trailingslash.test.ts', - 'test/e2e/app-dir/with-babel/with-babel.test.ts', - 'test/e2e/basepath-trailing-slash.test.ts', - 'test/e2e/basepath.test.ts', - 'test/e2e/browserslist/browserslist.test.ts', - 'test/e2e/browserslist/legacybrowsers-false.test.ts', - 'test/e2e/browserslist/legacybrowsers-true.test.ts', - 'test/e2e/edge-can-read-request-body/index.test.ts', - 'test/e2e/edge-can-use-wasm-files/index.test.ts', - 'test/e2e/edge-compiler-can-import-blob-assets/index.test.ts', - 'test/e2e/edge-configurable-runtime/index.test.ts', - 'test/e2e/edge-pages-support/index.test.ts', - 'test/e2e/fetch-failures-have-good-stack-traces-in-edge-runtime/fetch-failures-have-good-stack-traces-in-edge-runtime.test.ts', - 'test/e2e/getserversideprops/test/index.test.ts', - 'test/e2e/i18n-api-support/index.test.ts', - 'test/e2e/i18n-data-fetching-redirect/index.test.ts', - 'test/e2e/i18n-default-locale-redirect/i18n-default-locale-redirect.test.ts', - 'test/e2e/i18n-disallow-multiple-locales/i18n-disallow-multiple-locales.test.ts', - 'test/e2e/i18n-ignore-redirect-source-locale/redirects-with-basepath.test.ts', - 'test/e2e/i18n-ignore-redirect-source-locale/redirects.test.ts', - 'test/e2e/i18n-ignore-rewrite-source-locale/rewrites-with-basepath.test.ts', - 'test/e2e/i18n-ignore-rewrite-source-locale/rewrites.test.ts', - 'test/e2e/ignore-invalid-popstateevent/with-i18n.test.ts', - 'test/e2e/instrumentation-hook-src/instrumentation-hook-src.test.ts', - 'test/e2e/instrumentation-hook/instrumentation-hook.test.ts', - 'test/e2e/manual-client-base-path/index.test.ts', - 'test/e2e/middleware-custom-matchers-basepath/test/index.test.ts', - 'test/e2e/middleware-custom-matchers-i18n/test/index.test.ts', - 'test/e2e/middleware-custom-matchers/test/index.test.ts', - 'test/e2e/middleware-dynamic-basepath-matcher/test/index.test.ts', - 'test/e2e/middleware-fetches-with-any-http-method/index.test.ts', - 'test/e2e/middleware-fetches-with-body/index.test.ts', - 'test/e2e/middleware-matcher/index.test.ts', - 'test/e2e/middleware-redirects/test/index.test.ts', - 'test/e2e/middleware-request-header-overrides/test/index.test.ts', - 'test/e2e/middleware-rewrites/test/index.test.ts', - 'test/e2e/middleware-trailing-slash/test/index.test.ts', - 'test/e2e/next-font/basepath.test.ts', - 'test/e2e/next-font/google-fetch-error.test.ts', - 'test/e2e/next-font/index.test.ts', - 'test/e2e/next-font/with-font-declarations-file.test.ts', - 'test/e2e/next-font/with-proxy.test.ts', - 'test/e2e/next-font/without-preloaded-fonts.test.ts', - 'test/e2e/next-head/index.test.ts', - 'test/e2e/next-script/index.test.ts', - 'test/e2e/og-api/index.test.ts', - 'test/e2e/opentelemetry/opentelemetry.test.ts', - 'test/e2e/prerender-crawler.test.ts', - 'test/e2e/prerender.test.ts', - 'test/e2e/reload-scroll-backforward-restoration/index.test.ts', - 'test/e2e/skip-trailing-slash-redirect/index.test.ts', - 'test/e2e/streaming-ssr/index.test.ts', - 'test/e2e/swc-warnings/index.test.ts', - 'test/e2e/switchable-runtime/index.test.ts', - 'test/examples/examples.test.ts', - 'test/integration/404-page/test/index.test.js', - 'test/integration/500-page/test/index.test.js', - 'test/integration/amphtml-ssg/test/index.test.js', - 'test/integration/amphtml/test/index.test.js', - 'test/integration/api-support/test/index.test.js', - 'test/integration/app-dir-export/test/dynamicapiroute-dev.test.ts', - 'test/integration/app-dir-export/test/dynamicpage-dev.test.ts', - 'test/integration/app-dir-export/test/trailing-slash-dev.test.ts', - 'test/integration/app-document-add-hmr/test/index.test.js', - 'test/integration/app-document-import-order/test/index.test.js', - 'test/integration/app-document-remove-hmr/test/index.test.js', - 'test/integration/app-document/test/index.test.js', - 'test/integration/async-modules/test/index.test.js', - 'test/integration/auto-export/test/index.test.js', - 'test/integration/babel/test/index.test.js', - 'test/integration/basepath-root-catch-all/test/index.test.js', - 'test/integration/broken-webpack-plugin/test/index.test.js', - 'test/integration/build-indicator/test/index.test.js', - 'test/integration/build-spinners/index.test.ts', - 'test/integration/cli/test/index.test.js', - 'test/integration/client-navigation/test/index.test.js', - 'test/integration/compression/test/index.test.js', - 'test/integration/config-devtool-dev/test/index.test.js', - 'test/integration/config-mjs/test/index.test.js', - 'test/integration/config-output-export/test/index.test.ts', - 'test/integration/config/test/index.test.js', - 'test/integration/conflicting-app-page-error/test/index.test.js', - 'test/integration/conflicting-public-file-page/test/index.test.js', - 'test/integration/css/test/group-2.test.js', - 'test/integration/custom-error/test/index.test.js', - 'test/integration/custom-page-extension/test/index.test.js', - 'test/integration/custom-routes-catchall/test/index.test.js', - 'test/integration/custom-routes-i18n-index-redirect/test/index.test.js', - 'test/integration/custom-routes-i18n/test/index.test.js', - 'test/integration/custom-routes/test/index.test.js', - 'test/integration/custom-server/test/index.test.js', - 'test/integration/data-fetching-errors/test/index.test.js', - 'test/integration/development-runtime-config/test/index.test.js', - 'test/integration/draft-mode/test/index.test.ts', - 'test/integration/dynamic-optional-routing-root-fallback/test/index.test.js', - 'test/integration/dynamic-optional-routing-root-static-paths/test/index.test.js', - 'test/integration/dynamic-optional-routing/test/index.test.js', - 'test/integration/dynamic-routing/test/index.test.js', - 'test/integration/dynamic-routing/test/middleware.test.js', - 'test/integration/edge-runtime-configurable-guards/test/index.test.js', - 'test/integration/edge-runtime-dynamic-code/test/index.test.js', - 'test/integration/edge-runtime-module-errors/test/index.test.js', - 'test/integration/edge-runtime-response-error/test/index.test.js', - 'test/integration/edge-runtime-streaming-error/test/index.test.ts', - 'test/integration/edge-runtime-with-node.js-apis/test/index.test.ts', - 'test/integration/empty-project/test/index.test.js', - 'test/integration/env-config/test/index.test.js', - 'test/integration/fallback-false-rewrite/test/index.test.js', - 'test/integration/fallback-route-params/test/index.test.js', - 'test/integration/file-serving/test/index.test.js', - 'test/integration/getinitialprops/test/index.test.js', - 'test/integration/getserversideprops-preview/test/index.test.js', - 'test/integration/gssp-redirect-base-path/test/index.test.js', - 'test/integration/gssp-redirect-with-rewrites/test/index.test.js', - 'test/integration/gssp-redirect/test/index.test.js', - 'test/integration/i18n-support-base-path/test/index.test.js', - 'test/integration/i18n-support-catchall/test/index.test.js', - 'test/integration/i18n-support-custom-error/test/index.test.js', - 'test/integration/i18n-support-fallback-rewrite-legacy/test/index.test.js', - 'test/integration/i18n-support-fallback-rewrite/test/index.test.js', - 'test/integration/i18n-support-index-rewrite/test/index.test.js', - 'test/integration/i18n-support-same-page-hash-change/test/index.test.js', - 'test/integration/i18n-support/test/index.test.js', - 'test/integration/image-optimizer/test/content-disposition-type.test.ts', - 'test/integration/image-optimizer/test/index.test.ts', - 'test/integration/image-optimizer/test/minimum-cache-ttl.test.ts', - 'test/integration/image-optimizer/test/sharp.test.ts', - 'test/integration/image-optimizer/test/squoosh.test.ts', - 'test/integration/import-assertion/test/index.test.js', - 'test/integration/invalid-custom-routes/test/index.test.js', - 'test/integration/invalid-middleware-matchers/test/index.test.js', - 'test/integration/invalid-multi-match/test/index.test.js', - 'test/integration/jsconfig-baseurl/test/index.test.js', - 'test/integration/jsconfig-paths/test/index.test.js', - 'test/integration/link-with-encoding/test/index.test.js', - 'test/integration/middleware-dev-errors/test/index.test.js', - 'test/integration/middleware-dev-update/test/index.test.js', - 'test/integration/next-dynamic-lazy-compilation/test/index.test.js', - 'test/integration/next-image-legacy/asset-prefix/test/index.test.ts', - 'test/integration/next-image-legacy/base-path/test/index.test.ts', - 'test/integration/next-image-legacy/base-path/test/static.test.ts', - 'test/integration/next-image-legacy/default/test/index.test.ts', - 'test/integration/next-image-legacy/image-from-node-modules/test/index.test.ts', - 'test/integration/next-image-legacy/svgo-webpack/test/index.test.ts', - 'test/integration/next-image-legacy/trailing-slash/test/index.test.ts', - 'test/integration/next-image-legacy/typescript/test/index.test.ts', - 'test/integration/next-image-legacy/unicode/test/index.test.ts', - 'test/integration/next-image-new/app-dir/test/index.test.ts', - 'test/integration/next-image-new/app-dir/test/static.test.ts', - 'test/integration/next-image-new/asset-prefix/test/index.test.js', - 'test/integration/next-image-new/base-path/test/index.test.js', - 'test/integration/next-image-new/base-path/test/static.test.js', - 'test/integration/next-image-new/both-basepath-trailingslash/test/index.test.ts', - 'test/integration/next-image-new/default/test/index.test.ts', - 'test/integration/next-image-new/default/test/static.test.ts', - 'test/integration/next-image-new/export-config/test/index.test.ts', - 'test/integration/next-image-new/image-from-node-modules/test/index.test.ts', - 'test/integration/next-image-new/invalid-image-import/test/index.test.ts', - 'test/integration/next-image-new/loader-config-edge-runtime/test/index.test.ts', - 'test/integration/next-image-new/loader-config/test/index.test.ts', - 'test/integration/next-image-new/svgo-webpack/test/index.test.ts', - 'test/integration/next-image-new/typescript/test/index.test.ts', - 'test/integration/next-image-new/unicode/test/index.test.ts', - 'test/integration/no-duplicate-compile-error/test/index.test.js', - 'test/integration/no-override-next-props/test/index.test.js', - 'test/integration/node-fetch-keep-alive/test/index.test.js', - 'test/integration/nullish-config/test/index.test.js', - 'test/integration/prerender-fallback-encoding/test/index.test.js', - 'test/integration/prerender-preview/test/index.test.js', - 'test/integration/preview-fallback/test/index.test.js', - 'test/integration/process-env-stub/test/index.test.js', - 'test/integration/project-dir-delete/index.test.ts', - 'test/integration/react-18/test/index.test.js', - 'test/integration/relay-graphql-swc-multi-project/test/index.test.js', - 'test/integration/repeated-slashes/test/index.test.js', - 'test/integration/rewrite-with-browser-history/test/index.test.js', - 'test/integration/rewrites-client-resolving/test/index.test.js', - 'test/integration/rewrites-has-condition/test/index.test.js', - 'test/integration/rewrites-manual-href-as/test/index.test.js', - 'test/integration/route-index/test/index.test.js', - 'test/integration/script-loader/test/index.test.js', - 'test/integration/scroll-back-restoration/test/index.test.js', - 'test/integration/scroll-forward-restoration/test/index.test.js', - 'test/integration/server-asset-modules/test/index.test.js', - 'test/integration/server-side-dev-errors/test/index.test.js', - 'test/integration/telemetry/test/config.test.js', - 'test/integration/telemetry/test/index.test.js', - 'test/integration/telemetry/test/page-features.test.js', - 'test/integration/trailing-slash-dist/test/index.test.js', - 'test/integration/trailing-slashes-rewrite/test/index.test.js', - 'test/integration/trailing-slashes/test/index.test.js', - 'test/integration/turbopack-unsupported-log/index.test.ts', - 'test/integration/typescript-app-type-declarations/test/index.test.js', - 'test/integration/typescript-hmr/test/index.test.js', - 'test/integration/typescript-only-remove-type-imports/test/index.test.js', - 'test/integration/typescript-paths/test/index.test.js', - 'test/integration/typescript-version-warning/test/index.test.js', - 'test/integration/typescript-workspaces-paths/packages/www/test/index.test.js', - 'test/integration/typescript/test/index.test.js', - 'test/integration/undefined-webpack-config/test/index.test.js', - 'test/integration/url-imports/test/index.test.js', - 'test/integration/url/test/index.test.js', - 'test/integration/with-router/test/index.test.js', - 'test/integration/worker-webpack5/test/index.test.js', - 'test/production/app-dir-edge-runtime-with-wasm/index.test.ts', - 'test/production/app-dir-hide-suppressed-error-during-next-export/index.test.ts', - 'test/production/app-dir-prefetch-non-iso-url/index.test.ts', - 'test/production/app-dir/app-only-flag/app-only-flag.test.ts', - 'test/production/app-dir/revalidate/revalidate.test.ts', - 'test/production/ci-missing-typescript-deps/index.test.ts', - 'test/production/custom-error-500/index.test.ts', - 'test/production/custom-server/custom-server.test.ts', - 'test/production/dependencies-can-use-env-vars-in-middlewares/index.test.ts', - 'test/production/disable-fallback-polyfills/index.test.ts', - 'test/production/edge-config-validations/index.test.ts', - 'test/production/edge-runtime-is-addressable/index.test.ts', - 'test/production/emit-decorator-metadata/index.test.ts', - 'test/production/enoent-during-require/index.test.ts', - 'test/production/escheck-output/index.test.ts', - 'test/production/eslint-plugin-deps/index.test.ts', - 'test/production/export/index.test.ts', - 'test/production/exported-runtimes-value-validation/index.test.ts', - 'test/production/fallback-export-error/index.test.ts', - 'test/production/fatal-render-errror/index.test.ts', - 'test/production/generate-middleware-source-maps/index.test.ts', - 'test/production/jest/index.test.ts', - 'test/production/jest/new-link-behavior.test.ts', - 'test/production/jest/relay/relay-jest.test.ts', - 'test/production/jest/remove-react-properties/remove-react-properties-jest.test.ts', - 'test/production/jest/transpile-packages.test.ts', - 'test/production/middleware-environment-variables-in-node-server-reflect-the-usage-inference/index.test.ts', - 'test/production/middleware-typescript/test/index.test.ts', - 'test/production/next-font/babel-unsupported.test.ts', - 'test/production/next-font/telemetry-old.test.ts', - 'test/production/next-font/telemetry.test.ts', - 'test/production/pnpm-support/index.test.ts', - 'test/production/postcss-plugin-config-as-string/index.test.ts', - 'test/production/prerender-prefetch/index.test.ts', - 'test/production/reading-request-body-in-middleware/index.test.ts', - 'test/production/standalone-mode/metadata/index.test.ts', - 'test/production/standalone-mode/optimizecss/index.test.ts', - 'test/production/standalone-mode/required-server-files/required-server-files-app.test.ts', - 'test/production/standalone-mode/required-server-files/required-server-files-i18n.test.ts', - 'test/production/standalone-mode/required-server-files/required-server-files.test.ts', - 'test/production/standalone-mode/response-cache/index.test.ts', - 'test/production/standalone-mode/type-module/index.test.ts', - 'test/production/supports-module-resolution-nodenext/supports-moduleresolution-nodenext.test.ts', - 'test/production/typescript-basic/index.test.ts', - 'test/unit/accept-headers.test.ts', - 'test/unit/babel-plugin-next-page-config.test.ts', - 'test/unit/babel-plugin-next-ssg-transform.test.ts', - 'test/unit/cli.test.ts', - 'test/unit/cssnano-simple/cssnano-preset-simple/issue-1.test.ts', - 'test/unit/cssnano-simple/cssnano-preset-simple/plugin-config.test.ts', - 'test/unit/cssnano-simple/cssnano-preset-simple/property-sorting.test.ts', - 'test/unit/cssnano-simple/cssnano-simple/basic.test.ts', - 'test/unit/cssnano-simple/cssnano-simple/exclude-all.test.ts', - 'test/unit/cssnano-simple/cssnano-simple/plugin-config.test.ts', - 'test/unit/eslint-plugin-next/google-font-display.test.ts', - 'test/unit/eslint-plugin-next/google-font-preconnect.test.ts', - 'test/unit/eslint-plugin-next/index.test.ts', - 'test/unit/eslint-plugin-next/inline-script-id.test.ts', - 'test/unit/eslint-plugin-next/next-script-for-ga.test.ts', - 'test/unit/eslint-plugin-next/no-assign-module-variable.test.ts', - 'test/unit/eslint-plugin-next/no-before-interactive-script-outside-document.test.ts', - 'test/unit/eslint-plugin-next/no-css-tags.test.ts', - 'test/unit/eslint-plugin-next/no-document-import-in-page.test.ts', - 'test/unit/eslint-plugin-next/no-duplicate-head.test.ts', - 'test/unit/eslint-plugin-next/no-head-element.test.ts', - 'test/unit/eslint-plugin-next/no-head-import-in-document.test.ts', - 'test/unit/eslint-plugin-next/no-html-link-for-pages.test.ts', - 'test/unit/eslint-plugin-next/no-img-element.test.ts', - 'test/unit/eslint-plugin-next/no-page-custom-font.test.ts', - 'test/unit/eslint-plugin-next/no-script-component-in-head.test.ts', - 'test/unit/eslint-plugin-next/no-styled-jsx-in-document.test.ts', - 'test/unit/eslint-plugin-next/no-sync-scripts.test.ts', - 'test/unit/eslint-plugin-next/no-title-in-document-head.test.ts', - 'test/unit/eslint-plugin-next/no-typos.test.ts', - 'test/unit/eslint-plugin-next/no-unwanted-polyfillio.test.ts', - 'test/unit/esm-interpolate/esm-interpolate.test.tsx', - 'test/unit/find-config.test.ts', - 'test/unit/find-page-file.test.ts', - 'test/unit/get-module-build-info.test.ts', - 'test/unit/get-node-options-without-inspect.test.ts', - 'test/unit/get-page-static-infos.test.ts', - 'test/unit/get-project-dir.test.ts', - 'test/unit/getDisplayName.test.ts', - 'test/unit/htmlescape.test.ts', - 'test/unit/image-optimizer/detect-content-type.test.ts', - 'test/unit/image-optimizer/get-max-age.test.ts', - 'test/unit/image-optimizer/match-remote-pattern.test.ts', - 'test/unit/incremental-cache/file-system-cache.test.ts', - 'test/unit/infer-get-server-side-props-type.test.ts', - 'test/unit/infer-get-static-props.test.ts', - 'test/unit/is-equal-node.unit.test.ts', - 'test/unit/is-serializable-props.test.ts', - 'test/unit/isolated/config.test.ts', - 'test/unit/isolated/require-page.test.ts', - 'test/unit/jest-next-swc.test.ts', - 'test/unit/link-rendering.test.ts', - 'test/unit/link-warnings.test.tsx', - 'test/unit/loadGetInitialProps.test.ts', - 'test/unit/mitt.test.ts', - 'test/unit/next-babel-loader-dev.test.ts', - 'test/unit/next-babel-loader-prod.test.ts', - 'test/unit/next-babel.test.ts', - 'test/unit/next-dynamic.test.tsx', - 'test/unit/next-head-rendering.test.ts', - 'test/unit/next-image-legacy.test.ts', - 'test/unit/next-image-new.test.ts', - 'test/unit/next-server-utils.test.ts', - 'test/unit/next-swc.test.ts', - 'test/unit/oxford-comma.test.ts', - 'test/unit/page-route-sorter.test.ts', - 'test/unit/parse-page-static-info.test.ts', - 'test/unit/parse-relative-url.test.ts', - 'test/unit/phaseConstants.test.ts', - 'test/unit/preserve-process-env.test.ts', - 'test/unit/recursive-copy.test.ts', - 'test/unit/recursive-delete.test.ts', - 'test/unit/recursive-readdir.test.ts', - 'test/unit/router-add-base-path.test.ts', - 'test/unit/split-cookies-string.test.ts', - 'test/unit/validate-url.test.ts', - 'test/unit/warn-removed-experimental-config.test.ts', - 'test/unit/web-runtime/next-response-cookies.test.ts', - 'test/unit/web-runtime/next-response.test.ts', - 'test/unit/web-runtime/next-server-node.test.ts', - 'test/unit/web-runtime/next-url.test.ts', - 'test/unit/web-runtime/user-agent.test.ts', - 'test/unit/webpack-config-overrides.test.ts', - 'test/unit/write-app-declarations.test.ts', + 'test/e2e/app-dir/search-params-react-key/layout-params.test.ts', + 'test/e2e/app-dir/searchparams-static-bailout/searchparams-static-bailout.test.ts', + 'test/e2e/app-dir/similar-pages-paths/similar-pages-paths.test.ts', + 'test/e2e/app-dir/test-template/{{ toFileName name }}/{{ toFileName name }}.test.ts', + 'test/e2e/app-dir/underscore-ignore-app-paths/underscore-ignore-app-paths.test.ts', + 'test/e2e/app-dir/use-params/use-params.test.ts', + 'test/e2e/app-dir/use-selected-layout-segment-s/use-selected-layout-segment-s.test.ts', + 'test/e2e/browserslist-extends/index.test.ts', + 'test/e2e/config-promise-export/async-function.test.ts', + 'test/e2e/config-promise-export/promise.test.ts', + 'test/e2e/disable-js-preload/test/index.test.js', + 'test/e2e/dynamic-route-interpolation/index.test.ts', + 'test/e2e/edge-api-endpoints-can-receive-body/index.test.ts', + 'test/e2e/edge-async-local-storage/index.test.ts', + 'test/e2e/edge-compiler-module-exports-preference/index.test.ts', + 'test/e2e/edge-runtime-uses-edge-light-import-specifier-for-packages/edge-runtime-uses-edge-light-import-specifier-for-packages.test.ts', + 'test/e2e/handle-non-hoisted-swc-helpers/index.test.ts', + 'test/e2e/ignore-invalid-popstateevent/without-i18n.test.ts', + 'test/e2e/link-with-api-rewrite/index.test.ts', + 'test/e2e/middleware-base-path/test/index.test.ts', + 'test/e2e/middleware-general/test/index.test.ts', + 'test/e2e/middleware-responses/test/index.test.ts', + 'test/e2e/middleware-shallow-link/index.test.ts', + 'test/e2e/multi-zone/multi-zone.test.ts', + 'test/e2e/new-link-behavior/child-a-tag-error.test.ts', + 'test/e2e/new-link-behavior/index.test.ts', + 'test/e2e/new-link-behavior/material-ui.test.ts', + 'test/e2e/new-link-behavior/stitches.test.ts', + 'test/e2e/new-link-behavior/typescript.test.ts', + 'test/e2e/next-image-forward-ref/index.test.ts', + 'test/e2e/no-eslint-warn-with-no-eslint-config/index.test.ts', + 'test/e2e/nonce-head-manager/index.test.ts', + 'test/e2e/optimized-loading/test/index.test.ts', + 'test/e2e/postcss-config-cjs/index.test.ts', + 'test/e2e/prerender-native-module.test.ts', + 'test/e2e/proxy-request-with-middleware/test/index.test.ts', + 'test/e2e/repeated-forward-slashes-error/repeated-forward-slashes-error.test.ts', + 'test/e2e/ssr-react-context/index.test.ts', + 'test/e2e/styled-jsx/index.test.ts', + 'test/e2e/test-utils-tests/basic/basic.test.ts', + 'test/e2e/trailingslash-with-rewrite/index.test.ts', + 'test/e2e/transpile-packages/index.test.ts', + 'test/e2e/type-module-interop/index.test.ts', + 'test/e2e/undici-fetch/index.test.ts', + 'test/e2e/yarn-pnp/test/with-eslint.test.ts', + 'test/e2e/yarn-pnp/test/with-mdx.test.ts', + 'test/e2e/yarn-pnp/test/with-next-sass.test.ts', + 'test/integration/404-page-app/test/index.test.js', + 'test/integration/404-page-custom-error/test/index.test.js', + 'test/integration/404-page-ssg/test/index.test.js', + 'test/integration/absolute-assetprefix/test/index.test.js', + 'test/integration/amp-export-validation/test/index.test.js', + 'test/integration/amphtml-custom-optimizer/test/index.test.js', + 'test/integration/amphtml-custom-validator/test/index.test.js', + 'test/integration/amphtml-fragment-style/test/index.test.js', + 'test/integration/api-body-parser/test/index.test.js', + 'test/integration/api-catch-all/test/index.test.js', + 'test/integration/app-aspath/test/index.test.js', + 'test/integration/app-dir-export/test/config.test.ts', + 'test/integration/app-dir-export/test/dynamicapiroute-prod.test.ts', + 'test/integration/app-dir-export/test/dynamicpage-prod.test.ts', + 'test/integration/app-dir-export/test/start.test.ts', + 'test/integration/app-dir-export/test/trailing-slash-start.test.ts', + 'test/integration/app-document-style-fragment/test/index.test.js', + 'test/integration/app-dynamic-error/test/index.test.ts', + 'test/integration/app-functional/test/index.test.js', + 'test/integration/app-tree/test/index.test.js', + 'test/integration/app-types/app-types.test.js', + // TODO: should babel be tested with turbopack? + 'test/integration/babel-custom/test/index.test.js', + 'test/integration/bigint/test/index.test.js', + 'test/integration/catches-missing-getStaticProps/test/index.test.js', + 'test/integration/chunking/test/index.test.js', + 'test/integration/client-404/test/index.test.js', + 'test/integration/client-navigation-a11y/test/index.test.js', + 'test/integration/client-shallow-routing/test/index.test.js', + 'test/integration/config-experimental-warning/test/index.test.js', + 'test/integration/config-promise-error/test/index.test.js', + 'test/integration/config-resolve-alias/test/index.test.js', + 'test/integration/css-customization/test/index.test.js', + 'test/integration/css-features/test/index.test.js', + 'test/integration/css-minify/test/index.test.js', + 'test/integration/custom-error-page-exception/test/index.test.js', + 'test/integration/dedupes-scripts/test/index.test.js', + 'test/integration/development-hmr-refresh/test/index.test.js', + 'test/integration/disable-js/test/index.test.js', + 'test/integration/document-file-dependencies/test/index.test.js', + 'test/integration/document-head-warnings/test/index.test.js', + 'test/integration/duplicate-pages/test/index.test.js', + 'test/integration/dynamic-require/test/index.test.js', + 'test/integration/dynamic-route-rename/test/index.test.js', + 'test/integration/empty-object-getInitialProps/test/index.test.js', + 'test/integration/error-in-error/test/index.test.js', + 'test/integration/error-load-fail/test/index.test.js', + 'test/integration/error-plugin-stack-overflow/test/index.test.js', + 'test/integration/errors-on-output-to-public/test/index.test.js', + 'test/integration/errors-on-output-to-static/test/index.test.js', + 'test/integration/eslint/test/index.test.js', + 'test/integration/externalize-next-server/test/index.test.js', + 'test/integration/externals-esm-loose/test/index.test.js', + 'test/integration/externals-esm/test/index.test.js', + 'test/integration/fallback-modules/test/index.test.js', + 'test/integration/fetch-polyfill-ky-universal/test/index.test.js', + 'test/integration/fetch-polyfill/test/index.test.js', + 'test/integration/filesystempublicroutes/test/index.test.js', + 'test/integration/firebase-grpc/test/index.test.js', + 'test/integration/font-optimization/test/index.test.js', + 'test/integration/future/test/index.test.js', + 'test/integration/getserversideprops-export-error/test/index.test.js', + 'test/integration/gip-identifier/test/index.test.js', + 'test/integration/gsp-build-errors/test/index.test.js', + 'test/integration/gsp-extension/test/index.test.js', + 'test/integration/gssp-pageProps-merge/test/index.test.js', + 'test/integration/handles-export-errors/test/index.test.js', + 'test/integration/hashbang/test/index.test.js', + 'test/integration/hydrate-then-render/test/index.test.js', + 'test/integration/hydration/test/index.test.js', + 'test/integration/image-generation/test/index.test.ts', + 'test/integration/image-optimizer/test/old-sharp.test.ts', + 'test/integration/index-index/test/index.test.js', + 'test/integration/initial-ref/test/index.test.js', + 'test/integration/invalid-config-values/test/index.test.js', + 'test/integration/invalid-document-image-import/test/index.test.js', + 'test/integration/invalid-href/test/index.test.js', + 'test/integration/invalid-page-automatic-static-optimization/test/index.test.js', + 'test/integration/invalid-revalidate-values/test/index.test.js', + 'test/integration/invalid-server-options/test/index.test.js', + 'test/integration/jsconfig-empty/test/index.test.js', + 'test/integration/jsconfig/test/index.test.js', + 'test/integration/json-serialize-original-error/test/index.test.js', + 'test/integration/legacy-ssg-methods-error/test/index.test.js', + 'test/integration/link-ref/test/index.test.js', + 'test/integration/link-with-multiple-child/test/index.test.js', + 'test/integration/link-without-router/test/index.test.js', + 'test/integration/middleware-overrides-node.js-api/test/index.test.ts', + 'test/integration/middleware-prefetch/tests/index.test.js', + 'test/integration/middleware-src/test/index.test.js', + 'test/integration/missing-document-component-error/test/index.test.js', + 'test/integration/mixed-ssg-serverprops-error/test/index.test.js', + 'test/integration/next-dynamic/test/index.test.js', + 'test/integration/next-image-legacy/basic/test/index.test.ts', + 'test/integration/next-image-legacy/custom-resolver/test/index.test.ts', + 'test/integration/next-image-legacy/default/test/static.test.ts', + 'test/integration/next-image-legacy/no-intersection-observer-fallback/test/index.test.ts', + 'test/integration/next-image-legacy/noscript/test/index.test.ts', + 'test/integration/next-image-legacy/react-virtualized/test/index.test.ts', + 'test/integration/next-image-new/react-virtualized/test/index.test.ts', + 'test/integration/no-op-export/test/index.test.js', + 'test/integration/no-page-props/test/index.test.js', + 'test/integration/non-next-dist-exclude/test/index.test.js', + 'test/integration/non-standard-node-env-warning/test/index.test.js', + 'test/integration/not-found-revalidate/test/index.test.js', + 'test/integration/numeric-sep/test/index.test.js', + 'test/integration/ondemand/test/index.test.js', + 'test/integration/optional-chaining-nullish-coalescing/test/index.test.js', + 'test/integration/page-config/test/index.test.js', + 'test/integration/page-extensions/test/index.test.js', + 'test/integration/plugin-mdx-rs/test/index.test.js', + 'test/integration/polyfilling-minimal/test/index.test.js', + 'test/integration/polyfills/test/index.test.js', + 'test/integration/port-env-var/test/index.test.js', + 'test/integration/preload-viewport/test/index.test.js', + 'test/integration/prerender-invalid-catchall-params/test/index.test.js', + 'test/integration/prerender-invalid-paths/test/index.test.js', + 'test/integration/prerender-legacy/test/index.test.js', + 'test/integration/prerender-no-revalidate/test/index.test.js', + 'test/integration/prerender-revalidate/test/index.test.js', + 'test/integration/production-browser-sourcemaps/test/index.test.js', + 'test/integration/production-build-dir/test/index.test.js', + 'test/integration/production-config/test/index.test.js', + 'test/integration/production-nav/test/index.test.js', + 'test/integration/production-start-no-build/test/index.test.js', + 'test/integration/production/test/index.test.js', + 'test/integration/query-with-encoding/test/index.test.js', + 'test/integration/re-export-all-exports-from-page-disallowed/test/index.test.js', + 'test/integration/react-profiling-mode/test/index.test.js', + 'test/integration/react-streaming/test/index.test.js', + 'test/integration/read-only-source-hmr/test/index.test.js', + 'test/integration/relay-analytics-disabled/test/index.test.js', + 'test/integration/relay-analytics/test/index.test.js', + 'test/integration/render-error-on-module-error/test/index.test.js', + 'test/integration/render-error-on-top-level-error/with-get-initial-props/test/index.test.js', + 'test/integration/render-error-on-top-level-error/without-get-initial-props/test/index.test.js', + 'test/integration/required-server-files-ssr-404/test/index.test.js', + 'test/integration/revalidate-as-path/test/index.test.js', + 'test/integration/rewrites-destination-query-array/test/index.test.js', + 'test/integration/root-optional-revalidate/test/index.test.js', + 'test/integration/route-indexes/test/index.test.js', + 'test/integration/route-load-cancel-css/test/index.test.js', + 'test/integration/route-load-cancel/test/index.test.js', + 'test/integration/router-hash-navigation/test/index.test.js', + 'test/integration/router-is-ready-app-gip/test/index.test.js', + 'test/integration/router-is-ready/test/index.test.js', + 'test/integration/router-prefetch/test/index.test.js', + 'test/integration/scss/test/group-2.test.js', + 'test/integration/src-dir-support-double-dir/test/index.test.js', + 'test/integration/src-dir-support/test/index.test.js', + 'test/integration/ssg-data-404/test/index.test.js', + 'test/integration/ssg-dynamic-routes-404-page/test/index.test.js', + 'test/integration/static-404/test/index.test.js', + 'test/integration/static-page-name/test/index.test.js', + 'test/integration/styled-jsx-plugin/test/index.test.js', + 'test/integration/tsconfig-verifier/test/index.test.js', + 'test/integration/turbotrace-with-webpack-worker/test/index.test.js', + 'test/integration/typeof-window-replace/test/index.test.js', + 'test/integration/typescript-baseurl/test/index.test.js', + 'test/integration/typescript-custom-tsconfig/test/index.test.js', + 'test/integration/typescript-filtered-files/test/index.test.js', + 'test/integration/typescript-ignore-errors/test/index.test.js', + 'test/integration/webpack-config-extensionalias/test/index.test.js', + 'test/integration/webpack-config-mainjs/test/index.test.js', ] -module.exports = { - disabledTests, -} +module.exports = { enabledTests } diff --git a/run-tests.js b/run-tests.js index 4b353bae51..06cd05dda0 100644 --- a/run-tests.js +++ b/run-tests.js @@ -16,7 +16,7 @@ const exec = promisify(execOrig) // If process.argv contains a test to be executed, this'll append it to the list. const externalTestsFilterLists = process.env.NEXT_EXTERNAL_TESTS_FILTERS ? require(process.env.NEXT_EXTERNAL_TESTS_FILTERS) - : { enabledTests: [], disabledTests: [] } + : { enabledTests: [] } const timings = [] const DEFAULT_NUM_RETRIES = os.platform() === 'win32' ? 2 : 1 const DEFAULT_CONCURRENCY = 2 @@ -201,13 +201,11 @@ async function main() { } // If there are external manifest contains list of tests, apply it to the test lists. - // Specifically, we filters out `disabledTests` from named export of the manifest. - if (externalTestsFilterLists?.disabledTests.length > 0) { - tests = tests.filter( - (test) => - !externalTestsFilterLists.disabledTests.some((disabled) => - disabled.includes(test) - ) + if (externalTestsFilterLists?.enabledTests.length > 0) { + tests = tests.filter((test) => + externalTestsFilterLists.enabledTests.some((enabled) => + enabled.includes(test) + ) ) } diff --git a/test/development/basic/project-directory-rename.test.ts b/test/development/basic/project-directory-rename.test.ts index a261cb618c..e1e628777d 100644 --- a/test/development/basic/project-directory-rename.test.ts +++ b/test/development/basic/project-directory-rename.test.ts @@ -5,7 +5,8 @@ import { NextInstance } from 'test/lib/next-modes/base' import { createNext } from 'e2e-utils' import stripAnsi from 'strip-ansi' -describe('Project Directory Renaming', () => { +// TODO: investigate occasional failure +describe.skip('Project Directory Renaming', () => { let next: NextInstance beforeAll(async () => { diff --git a/test/e2e/app-dir/actions/app-action.test.ts b/test/e2e/app-dir/actions/app-action.test.ts index d22af5ab35..56b092c893 100644 --- a/test/e2e/app-dir/actions/app-action.test.ts +++ b/test/e2e/app-dir/actions/app-action.test.ts @@ -407,7 +407,8 @@ createNextDescribe( }, 'success') }) - it('should handle revalidateTag', async () => { + // TODO: investigate flakiness when deployed + it.skip('should handle revalidateTag', async () => { const browser = await next.browser('/revalidate') const randomNumber = await browser.elementByCss('#random-number').text() const justPutIt = await browser.elementByCss('#justputit').text() @@ -415,24 +416,21 @@ createNextDescribe( await browser.elementByCss('#revalidate-justputit').click() - // TODO: investigate flakiness when deployed - if (!isNextDeploy) { - await check(async () => { - const newRandomNumber = await browser - .elementByCss('#random-number') - .text() - const newJustPutIt = await browser.elementByCss('#justputit').text() - const newThankYouNext = await browser - .elementByCss('#thankyounext') - .text() + await check(async () => { + const newRandomNumber = await browser + .elementByCss('#random-number') + .text() + const newJustPutIt = await browser.elementByCss('#justputit').text() + const newThankYouNext = await browser + .elementByCss('#thankyounext') + .text() - expect(newRandomNumber).not.toBe(randomNumber) - expect(newJustPutIt).not.toBe(justPutIt) - expect(newThankYouNext).toBe(thankYouNext) + expect(newRandomNumber).not.toBe(randomNumber) + expect(newJustPutIt).not.toBe(justPutIt) + expect(newThankYouNext).toBe(thankYouNext) - return 'success' - }, 'success') - } + return 'success' + }, 'success') }) it('should handle revalidateTag + redirect', async () => { diff --git a/test/integration/500-page/test/gsp-gssp.test.js b/test/integration/500-page/test/gsp-gssp.test.js new file mode 100644 index 0000000000..fd5920bcc5 --- /dev/null +++ b/test/integration/500-page/test/gsp-gssp.test.js @@ -0,0 +1,238 @@ +/* eslint-env jest */ + +import fs from 'fs-extra' +import { join } from 'path' +import { + killApp, + findPort, + launchApp, + nextStart, + nextBuild, + renderViaHTTP, + waitFor, +} from 'next-test-utils' + +const appDir = join(__dirname, '../') +const pages500 = join(appDir, 'pages/500.js') +const pagesApp = join(appDir, 'pages/_app.js') +const pagesError = join(appDir, 'pages/_error.js') +const gip500Err = + /`pages\/500` can not have getInitialProps\/getServerSideProps/ + +let appPort +let app + +it('does not show error with getStaticProps in pages/500 build', async () => { + await fs.move(pages500, `${pages500}.bak`) + await fs.writeFile( + pages500, + ` + const page = () => 'custom 500 page' + export const getStaticProps = () => ({ props: { a: 'b' } }) + export default page + ` + ) + await fs.remove(join(appDir, '.next')) + const { stderr, code } = await nextBuild(appDir, [], { stderr: true }) + await fs.remove(pages500) + await fs.move(`${pages500}.bak`, pages500) + + expect(stderr).not.toMatch(gip500Err) + expect(code).toBe(0) +}) + +it('does not show error with getStaticProps in pages/500 dev', async () => { + await fs.move(pages500, `${pages500}.bak`) + await fs.writeFile( + pages500, + ` + const page = () => 'custom 500 page' + export const getStaticProps = () => ({ props: { a: 'b' } }) + export default page + ` + ) + + let stderr = '' + appPort = await findPort() + app = await launchApp(appDir, appPort, { + onStderr(msg) { + stderr += msg || '' + }, + }) + await renderViaHTTP(appPort, '/abc') + await waitFor(1000) + + await killApp(app) + + await fs.remove(pages500) + await fs.move(`${pages500}.bak`, pages500) + + expect(stderr).not.toMatch(gip500Err) +}) + +it('shows error with getServerSideProps in pages/500 build', async () => { + await fs.move(pages500, `${pages500}.bak`) + await fs.writeFile( + pages500, + ` + const page = () => 'custom 500 page' + export const getServerSideProps = () => ({ props: { a: 'b' } }) + export default page + ` + ) + await fs.remove(join(appDir, '.next')) + const { stderr, code } = await nextBuild(appDir, [], { stderr: true }) + await fs.remove(pages500) + await fs.move(`${pages500}.bak`, pages500) + + expect(stderr).toMatch(gip500Err) + expect(code).toBe(1) +}) + +it('shows error with getServerSideProps in pages/500 dev', async () => { + await fs.move(pages500, `${pages500}.bak`) + await fs.writeFile( + pages500, + ` + const page = () => 'custom 500 page' + export const getServerSideProps = () => ({ props: { a: 'b' } }) + export default page + ` + ) + + let stderr = '' + appPort = await findPort() + app = await launchApp(appDir, appPort, { + onStderr(msg) { + stderr += msg || '' + }, + }) + await renderViaHTTP(appPort, '/500') + await waitFor(1000) + + await killApp(app) + + await fs.remove(pages500) + await fs.move(`${pages500}.bak`, pages500) + + expect(stderr).toMatch(gip500Err) +}) + +it('does build 500 statically with getInitialProps in _app and getStaticProps in pages/500', async () => { + await fs.writeFile( + pagesApp, + ` + import App from 'next/app' + + const page = ({ Component, pageProps }) => + page.getInitialProps = (ctx) => App.getInitialProps(ctx) + export default page + ` + ) + await fs.rename(pages500, `${pages500}.bak`) + await fs.writeFile( + pages500, + ` + const page = () => { + console.log('rendered 500') + return 'custom 500 page' + } + export default page + + export const getStaticProps = () => { + return { + props: {} + } + } + ` + ) + await fs.remove(join(appDir, '.next')) + const { + stderr, + stdout: buildStdout, + code, + } = await nextBuild(appDir, [], { + stderr: true, + stdout: true, + }) + + await fs.remove(pagesApp) + await fs.remove(pages500) + await fs.rename(`${pages500}.bak`, pages500) + + expect(stderr).not.toMatch(gip500Err) + expect(buildStdout).toContain('rendered 500') + expect(code).toBe(0) + expect(await fs.pathExists(join(appDir, '.next/server/pages/500.html'))).toBe( + true + ) + + let appStdout = '' + const appPort = await findPort() + const app = await nextStart(appDir, appPort, { + onStdout(msg) { + appStdout += msg || '' + }, + onStderr(msg) { + appStdout += msg || '' + }, + }) + + await renderViaHTTP(appPort, '/err') + await killApp(app) + + expect(appStdout).not.toContain('rendered 500') +}) + +it('does not build 500 statically with no pages/500 and getServerSideProps in _error', async () => { + await fs.rename(pages500, `${pages500}.bak`) + await fs.writeFile( + pagesError, + ` + function Error({ statusCode }) { + return

Error status: {statusCode}

+ } + + export const getServerSideProps = ({ req, res, err }) => { + console.error('called _error getServerSideProps') + + if (req.url === '/500') { + throw new Error('should not export /500') + } + + return { + props: { + statusCode: res && res.statusCode ? res.statusCode : err ? err.statusCode : 404 + } + } + } + + export default Error + ` + ) + await fs.remove(join(appDir, '.next')) + const { stderr: buildStderr, code } = await nextBuild(appDir, [], { + stderr: true, + }) + await fs.rename(`${pages500}.bak`, pages500) + await fs.remove(pagesError) + console.log(buildStderr) + expect(buildStderr).not.toMatch(gip500Err) + expect(code).toBe(0) + expect(await fs.pathExists(join(appDir, '.next/server/pages/500.html'))).toBe( + false + ) + + let appStderr = '' + const appPort = await findPort() + const app = await nextStart(appDir, appPort, { + onStderr(msg) { + appStderr += msg || '' + }, + }) + + await renderViaHTTP(appPort, '/err') + await killApp(app) + + expect(appStderr).toContain('called _error getServerSideProps') +}) diff --git a/test/integration/500-page/test/index.test.js b/test/integration/500-page/test/index.test.js index dceebd117b..bedf93ef31 100644 --- a/test/integration/500-page/test/index.test.js +++ b/test/integration/500-page/test/index.test.js @@ -130,72 +130,6 @@ describe('500 Page Support', () => { expect(appStdout).toContain('rendered 500') }) - it('does build 500 statically with getInitialProps in _app and getStaticProps in pages/500', async () => { - await fs.writeFile( - pagesApp, - ` - import App from 'next/app' - - const page = ({ Component, pageProps }) => - page.getInitialProps = (ctx) => App.getInitialProps(ctx) - export default page - ` - ) - await fs.rename(pages500, `${pages500}.bak`) - await fs.writeFile( - pages500, - ` - const page = () => { - console.log('rendered 500') - return 'custom 500 page' - } - export default page - - export const getStaticProps = () => { - return { - props: {} - } - } - ` - ) - await fs.remove(join(appDir, '.next')) - const { - stderr, - stdout: buildStdout, - code, - } = await nextBuild(appDir, [], { - stderr: true, - stdout: true, - }) - - await fs.remove(pagesApp) - await fs.remove(pages500) - await fs.rename(`${pages500}.bak`, pages500) - - expect(stderr).not.toMatch(gip500Err) - expect(buildStdout).toContain('rendered 500') - expect(code).toBe(0) - expect( - await fs.pathExists(join(appDir, '.next/server/pages/500.html')) - ).toBe(true) - - let appStdout = '' - const appPort = await findPort() - const app = await nextStart(appDir, appPort, { - onStdout(msg) { - appStdout += msg || '' - }, - onStderr(msg) { - appStdout += msg || '' - }, - }) - - await renderViaHTTP(appPort, '/err') - await killApp(app) - - expect(appStdout).not.toContain('rendered 500') - }) - it('builds 500 statically by default with no pages/500', async () => { await fs.rename(pages500, `${pages500}.bak`) await fs.remove(join(appDir, '.next')) @@ -311,59 +245,6 @@ describe('500 Page Support', () => { expect(appStderr).toContain('called _error.getInitialProps') }) - it('does not build 500 statically with no pages/500 and getServerSideProps in _error', async () => { - await fs.rename(pages500, `${pages500}.bak`) - await fs.writeFile( - pagesError, - ` - function Error({ statusCode }) { - return

Error status: {statusCode}

- } - - export const getServerSideProps = ({ req, res, err }) => { - console.error('called _error getServerSideProps') - - if (req.url === '/500') { - throw new Error('should not export /500') - } - - return { - props: { - statusCode: res && res.statusCode ? res.statusCode : err ? err.statusCode : 404 - } - } - } - - export default Error - ` - ) - await fs.remove(join(appDir, '.next')) - const { stderr: buildStderr, code } = await nextBuild(appDir, [], { - stderr: true, - }) - await fs.rename(`${pages500}.bak`, pages500) - await fs.remove(pagesError) - console.log(buildStderr) - expect(buildStderr).not.toMatch(gip500Err) - expect(code).toBe(0) - expect( - await fs.pathExists(join(appDir, '.next/server/pages/500.html')) - ).toBe(false) - - let appStderr = '' - const appPort = await findPort() - const app = await nextStart(appDir, appPort, { - onStderr(msg) { - appStderr += msg || '' - }, - }) - - await renderViaHTTP(appPort, '/err') - await killApp(app) - - expect(appStderr).toContain('called _error getServerSideProps') - }) - it('does not build 500 statically with no pages/500 and custom getInitialProps in _error and _app', async () => { await fs.rename(pages500, `${pages500}.bak`) await fs.writeFile( @@ -471,100 +352,4 @@ describe('500 Page Support', () => { expect(stderr).toMatch(gip500Err) }) - - it('does not show error with getStaticProps in pages/500 build', async () => { - await fs.move(pages500, `${pages500}.bak`) - await fs.writeFile( - pages500, - ` - const page = () => 'custom 500 page' - export const getStaticProps = () => ({ props: { a: 'b' } }) - export default page - ` - ) - await fs.remove(join(appDir, '.next')) - const { stderr, code } = await nextBuild(appDir, [], { stderr: true }) - await fs.remove(pages500) - await fs.move(`${pages500}.bak`, pages500) - - expect(stderr).not.toMatch(gip500Err) - expect(code).toBe(0) - }) - - it('does not show error with getStaticProps in pages/500 dev', async () => { - await fs.move(pages500, `${pages500}.bak`) - await fs.writeFile( - pages500, - ` - const page = () => 'custom 500 page' - export const getStaticProps = () => ({ props: { a: 'b' } }) - export default page - ` - ) - - let stderr = '' - appPort = await findPort() - app = await launchApp(appDir, appPort, { - onStderr(msg) { - stderr += msg || '' - }, - }) - await renderViaHTTP(appPort, '/abc') - await waitFor(1000) - - await killApp(app) - - await fs.remove(pages500) - await fs.move(`${pages500}.bak`, pages500) - - expect(stderr).not.toMatch(gip500Err) - }) - - it('shows error with getServerSideProps in pages/500 build', async () => { - await fs.move(pages500, `${pages500}.bak`) - await fs.writeFile( - pages500, - ` - const page = () => 'custom 500 page' - export const getServerSideProps = () => ({ props: { a: 'b' } }) - export default page - ` - ) - await fs.remove(join(appDir, '.next')) - const { stderr, code } = await nextBuild(appDir, [], { stderr: true }) - await fs.remove(pages500) - await fs.move(`${pages500}.bak`, pages500) - - expect(stderr).toMatch(gip500Err) - expect(code).toBe(1) - }) - - it('shows error with getServerSideProps in pages/500 dev', async () => { - await fs.move(pages500, `${pages500}.bak`) - await fs.writeFile( - pages500, - ` - const page = () => 'custom 500 page' - export const getServerSideProps = () => ({ props: { a: 'b' } }) - export default page - ` - ) - - let stderr = '' - appPort = await findPort() - app = await launchApp(appDir, appPort, { - onStderr(msg) { - stderr += msg || '' - }, - }) - await renderViaHTTP(appPort, '/500') - await waitFor(1000) - - await killApp(app) - - await fs.remove(pages500) - await fs.move(`${pages500}.bak`, pages500) - - expect(stderr).toMatch(gip500Err) - }) }) diff --git a/test/integration/create-next-app/index.test.ts b/test/integration/create-next-app/index.test.ts index 2eb8f2c37c..50e130de0f 100644 --- a/test/integration/create-next-app/index.test.ts +++ b/test/integration/create-next-app/index.test.ts @@ -475,416 +475,4 @@ describe('create next app', () => { shouldBeJavascriptProject({ cwd, projectName, template: 'app' }) }) }) - - it('should use npm as the package manager on supplying --use-npm', async () => { - await useTempDir(async (cwd) => { - const projectName = 'use-npm' - const res = await run( - [ - projectName, - '--js', - '--no-tailwind', - '--eslint', - '--use-npm', - '--no-src-dir', - '--app', - `--import-alias=@/*`, - ], - { - cwd, - } - ) - - expect(res.exitCode).toBe(0) - shouldBeJavascriptProject({ cwd, projectName, template: 'app' }) - }) - }) - - it('should use npm as the package manager on supplying --use-npm with example', async () => { - await useTempDir(async (cwd) => { - const projectName = 'use-npm' - const res = await run( - [ - projectName, - '--js', - '--no-tailwind', - '--eslint', - '--use-npm', - '--example', - `${exampleRepo}/${examplePath}`, - ], - { cwd } - ) - - expect(res.exitCode).toBe(0) - projectFilesShouldExist({ - cwd, - projectName, - files: [ - 'package.json', - 'pages/index.tsx', - '.gitignore', - 'package-lock.json', - 'node_modules/next', - ], - }) - }) - }) - - it('should use Yarn as the package manager on supplying --use-yarn', async () => { - await useTempDir(async (cwd) => { - const projectName = 'use-yarn' - const res = await run( - [ - projectName, - '--js', - '--no-tailwind', - '--eslint', - '--use-yarn', - '--no-src-dir', - '--app', - `--import-alias=@/*`, - ], - { - cwd, - } - ) - - expect(res.exitCode).toBe(0) - projectFilesShouldExist({ - cwd, - projectName, - files: [ - 'package.json', - 'app/page.js', - '.gitignore', - '.eslintrc.json', - 'yarn.lock', - 'node_modules/next', - ], - }) - }) - }) - - it('should use Yarn as the package manager on supplying --use-yarn with example', async () => { - try { - await execa('yarn', ['--version']) - } catch (_) { - // install yarn if not available - await execa('npm', ['i', '-g', 'yarn']) - } - - await useTempDir(async (cwd) => { - const projectName = 'use-yarn' - const res = await run( - [ - projectName, - '--js', - '--no-tailwind', - '--eslint', - '--use-yarn', - '--example', - `${exampleRepo}/${examplePath}`, - ], - { cwd } - ) - - expect(res.exitCode).toBe(0) - projectFilesShouldExist({ - cwd, - projectName, - files: [ - 'package.json', - 'pages/index.tsx', - '.gitignore', - 'yarn.lock', - 'node_modules/next', - ], - }) - }) - }) - - it('should use pnpm as the package manager on supplying --use-pnpm', async () => { - await useTempDir(async (cwd) => { - const projectName = 'use-pnpm' - const res = await run( - [ - projectName, - '--js', - '--no-tailwind', - '--eslint', - '--use-pnpm', - '--no-src-dir', - '--app', - `--import-alias=@/*`, - ], - { - cwd, - } - ) - - expect(res.exitCode).toBe(0) - projectFilesShouldExist({ - cwd, - projectName, - files: [ - 'package.json', - 'app/page.js', - '.gitignore', - '.eslintrc.json', - 'pnpm-lock.yaml', - 'node_modules/next', - ], - }) - }) - }) - - it('should use pnpm as the package manager on supplying --use-pnpm with example', async () => { - try { - await execa('pnpm', ['--version']) - } catch (_) { - // install pnpm if not available - await execa('npm', ['i', '-g', 'pnpm']) - } - - await useTempDir(async (cwd) => { - const projectName = 'use-pnpm' - const res = await run( - [ - projectName, - '--js', - '--no-tailwind', - '--eslint', - '--use-pnpm', - '--example', - `${exampleRepo}/${examplePath}`, - ], - { cwd } - ) - - expect(res.exitCode).toBe(0) - projectFilesShouldExist({ - cwd, - projectName, - files: [ - 'package.json', - 'pages/index.tsx', - '.gitignore', - 'pnpm-lock.yaml', - 'node_modules/next', - ], - }) - }) - }) - - it('should infer npm as the package manager', async () => { - await useTempDir(async (cwd) => { - const projectName = 'infer-package-manager-npm' - const res = await run( - [ - projectName, - '--js', - '--no-tailwind', - '--eslint', - '--no-src-dir', - '--app', - `--import-alias=@/*`, - ], - { - cwd, - env: { ...process.env, npm_config_user_agent: 'npm' }, - } - ) - - const files = [ - 'package.json', - 'app/page.js', - '.gitignore', - '.eslintrc.json', - 'package-lock.json', - 'node_modules/next', - ] - - expect(res.exitCode).toBe(0) - projectFilesShouldExist({ cwd, projectName, files }) - }) - }) - - it('should infer npm as the package manager with example', async () => { - await useTempDir(async (cwd) => { - const projectName = 'infer-package-manager-npm' - const res = await run( - [ - projectName, - '--js', - '--no-tailwind', - '--eslint', - '--example', - `${exampleRepo}/${examplePath}`, - ], - { cwd, env: { ...process.env, npm_config_user_agent: 'npm' } } - ) - - const files = [ - 'package.json', - 'pages/index.tsx', - '.gitignore', - 'package-lock.json', - 'node_modules/next', - ] - - expect(res.exitCode).toBe(0) - projectFilesShouldExist({ cwd, projectName, files }) - }) - }) - - it('should infer yarn as the package manager', async () => { - try { - await execa('yarn', ['--version']) - } catch (_) { - // install yarn if not available - await execa('npm', ['i', '-g', 'yarn']) - } - - await useTempDir(async (cwd) => { - const projectName = 'infer-package-manager-yarn' - const res = await run( - [ - projectName, - '--js', - '--no-tailwind', - '--eslint', - '--no-src-dir', - '--app', - `--import-alias=@/*`, - ], - { - cwd, - env: { ...process.env, npm_config_user_agent: 'yarn' }, - } - ) - - const files = [ - 'package.json', - 'app/page.js', - '.gitignore', - '.eslintrc.json', - 'yarn.lock', - 'node_modules/next', - ] - - expect(res.exitCode).toBe(0) - projectFilesShouldExist({ cwd, projectName, files }) - }) - }) - - it('should infer yarn as the package manager with example', async () => { - try { - await execa('yarn', ['--version']) - } catch (_) { - // install yarn if not available - await execa('npm', ['i', '-g', 'yarn']) - } - - await useTempDir(async (cwd) => { - const projectName = 'infer-package-manager-npm' - const res = await run( - [ - projectName, - '--js', - '--no-tailwind', - '--eslint', - '--example', - `${exampleRepo}/${examplePath}`, - ], - { cwd, env: { ...process.env, npm_config_user_agent: 'yarn' } } - ) - - const files = [ - 'package.json', - 'pages/index.tsx', - '.gitignore', - 'yarn.lock', - 'node_modules/next', - ] - - expect(res.exitCode).toBe(0) - projectFilesShouldExist({ cwd, projectName, files }) - }) - }) - - it('should infer pnpm as the package manager', async () => { - try { - await execa('pnpm', ['--version']) - } catch (_) { - // install pnpm if not available - await execa('npm', ['i', '-g', 'pnpm']) - } - - await useTempDir(async (cwd) => { - const projectName = 'infer-package-manager' - const res = await run( - [ - projectName, - '--js', - '--no-tailwind', - '--eslint', - '--no-src-dir', - '--app', - `--import-alias=@/*`, - ], - { - cwd, - env: { ...process.env, npm_config_user_agent: 'pnpm' }, - } - ) - - const files = [ - 'package.json', - 'app/page.js', - '.gitignore', - '.eslintrc.json', - 'pnpm-lock.yaml', - 'node_modules/next', - ] - - expect(res.exitCode).toBe(0) - projectFilesShouldExist({ cwd, projectName, files }) - }) - }) - - it('should infer pnpm as the package manager with example', async () => { - try { - await execa('pnpm', ['--version']) - } catch (_) { - // install pnpm if not available - await execa('npm', ['i', '-g', 'pnpm']) - } - - await useTempDir(async (cwd) => { - const projectName = 'infer-package-manager-npm' - const res = await run( - [ - projectName, - '--js', - '--no-tailwind', - '--eslint', - '--example', - `${exampleRepo}/${examplePath}`, - ], - { cwd, env: { ...process.env, npm_config_user_agent: 'pnpm' } } - ) - - const files = [ - 'package.json', - 'pages/index.tsx', - '.gitignore', - 'pnpm-lock.yaml', - 'node_modules/next', - ] - - expect(res.exitCode).toBe(0) - projectFilesShouldExist({ cwd, projectName, files }) - }) - }) }) diff --git a/test/integration/create-next-app/package-manager.test.ts b/test/integration/create-next-app/package-manager.test.ts new file mode 100644 index 0000000000..d0c1e12b3e --- /dev/null +++ b/test/integration/create-next-app/package-manager.test.ts @@ -0,0 +1,438 @@ +/* eslint-env jest */ +/** + * @fileoverview + * + * This file contains integration tests for `create-next-app`. It currently + * aliases all calls to `--js`. + * + * TypeScript project creation via `create-next-app --ts` is tested in + * `./templates.test.ts`, though additional tests can be added here using the + * `shouldBeTypescriptProject` helper. + */ + +import execa from 'execa' +import Conf from 'next/dist/compiled/conf' +import { useTempDir } from '../../lib/use-temp-dir' +import { projectFilesShouldExist, shouldBeJavascriptProject } from './lib/utils' + +const cli = require.resolve('create-next-app/dist/index.js') +const exampleRepo = 'https://github.com/vercel/next.js/tree/canary' +const examplePath = 'examples/basic-css' + +const run = (args: string[], options: execa.Options) => { + const conf = new Conf({ projectName: 'create-next-app' }) + conf.clear() + return execa('node', [cli].concat(args), options) +} + +it('should use npm as the package manager on supplying --use-npm', async () => { + await useTempDir(async (cwd) => { + const projectName = 'use-npm' + const res = await run( + [ + projectName, + '--js', + '--no-tailwind', + '--eslint', + '--use-npm', + '--no-src-dir', + '--app', + `--import-alias=@/*`, + ], + { + cwd, + } + ) + + expect(res.exitCode).toBe(0) + shouldBeJavascriptProject({ cwd, projectName, template: 'app' }) + }) +}) + +it('should use npm as the package manager on supplying --use-npm with example', async () => { + await useTempDir(async (cwd) => { + const projectName = 'use-npm' + const res = await run( + [ + projectName, + '--js', + '--no-tailwind', + '--eslint', + '--use-npm', + '--example', + `${exampleRepo}/${examplePath}`, + ], + { cwd } + ) + + expect(res.exitCode).toBe(0) + projectFilesShouldExist({ + cwd, + projectName, + files: [ + 'package.json', + 'pages/index.tsx', + '.gitignore', + 'package-lock.json', + 'node_modules/next', + ], + }) + }) +}) + +it('should use Yarn as the package manager on supplying --use-yarn', async () => { + await useTempDir(async (cwd) => { + const projectName = 'use-yarn' + const res = await run( + [ + projectName, + '--js', + '--no-tailwind', + '--eslint', + '--use-yarn', + '--no-src-dir', + '--app', + `--import-alias=@/*`, + ], + { + cwd, + } + ) + + expect(res.exitCode).toBe(0) + projectFilesShouldExist({ + cwd, + projectName, + files: [ + 'package.json', + 'app/page.js', + '.gitignore', + '.eslintrc.json', + 'yarn.lock', + 'node_modules/next', + ], + }) + }) +}) + +it('should use Yarn as the package manager on supplying --use-yarn with example', async () => { + try { + await execa('yarn', ['--version']) + } catch (_) { + // install yarn if not available + await execa('npm', ['i', '-g', 'yarn']) + } + + await useTempDir(async (cwd) => { + const projectName = 'use-yarn' + const res = await run( + [ + projectName, + '--js', + '--no-tailwind', + '--eslint', + '--use-yarn', + '--example', + `${exampleRepo}/${examplePath}`, + ], + { cwd } + ) + + expect(res.exitCode).toBe(0) + projectFilesShouldExist({ + cwd, + projectName, + files: [ + 'package.json', + 'pages/index.tsx', + '.gitignore', + 'yarn.lock', + 'node_modules/next', + ], + }) + }) +}) + +it('should use pnpm as the package manager on supplying --use-pnpm', async () => { + await useTempDir(async (cwd) => { + const projectName = 'use-pnpm' + const res = await run( + [ + projectName, + '--js', + '--no-tailwind', + '--eslint', + '--use-pnpm', + '--no-src-dir', + '--app', + `--import-alias=@/*`, + ], + { + cwd, + } + ) + + expect(res.exitCode).toBe(0) + projectFilesShouldExist({ + cwd, + projectName, + files: [ + 'package.json', + 'app/page.js', + '.gitignore', + '.eslintrc.json', + 'pnpm-lock.yaml', + 'node_modules/next', + ], + }) + }) +}) + +it('should use pnpm as the package manager on supplying --use-pnpm with example', async () => { + try { + await execa('pnpm', ['--version']) + } catch (_) { + // install pnpm if not available + await execa('npm', ['i', '-g', 'pnpm']) + } + + await useTempDir(async (cwd) => { + const projectName = 'use-pnpm' + const res = await run( + [ + projectName, + '--js', + '--no-tailwind', + '--eslint', + '--use-pnpm', + '--example', + `${exampleRepo}/${examplePath}`, + ], + { cwd } + ) + + expect(res.exitCode).toBe(0) + projectFilesShouldExist({ + cwd, + projectName, + files: [ + 'package.json', + 'pages/index.tsx', + '.gitignore', + 'pnpm-lock.yaml', + 'node_modules/next', + ], + }) + }) +}) + +it('should infer npm as the package manager', async () => { + await useTempDir(async (cwd) => { + const projectName = 'infer-package-manager-npm' + const res = await run( + [ + projectName, + '--js', + '--no-tailwind', + '--eslint', + '--no-src-dir', + '--app', + `--import-alias=@/*`, + ], + { + cwd, + env: { ...process.env, npm_config_user_agent: 'npm' }, + } + ) + + const files = [ + 'package.json', + 'app/page.js', + '.gitignore', + '.eslintrc.json', + 'package-lock.json', + 'node_modules/next', + ] + + expect(res.exitCode).toBe(0) + projectFilesShouldExist({ cwd, projectName, files }) + }) +}) + +it('should infer npm as the package manager with example', async () => { + await useTempDir(async (cwd) => { + const projectName = 'infer-package-manager-npm' + const res = await run( + [ + projectName, + '--js', + '--no-tailwind', + '--eslint', + '--example', + `${exampleRepo}/${examplePath}`, + ], + { cwd, env: { ...process.env, npm_config_user_agent: 'npm' } } + ) + + const files = [ + 'package.json', + 'pages/index.tsx', + '.gitignore', + 'package-lock.json', + 'node_modules/next', + ] + + expect(res.exitCode).toBe(0) + projectFilesShouldExist({ cwd, projectName, files }) + }) +}) + +it('should infer yarn as the package manager', async () => { + try { + await execa('yarn', ['--version']) + } catch (_) { + // install yarn if not available + await execa('npm', ['i', '-g', 'yarn']) + } + + await useTempDir(async (cwd) => { + const projectName = 'infer-package-manager-yarn' + const res = await run( + [ + projectName, + '--js', + '--no-tailwind', + '--eslint', + '--no-src-dir', + '--app', + `--import-alias=@/*`, + ], + { + cwd, + env: { ...process.env, npm_config_user_agent: 'yarn' }, + } + ) + + const files = [ + 'package.json', + 'app/page.js', + '.gitignore', + '.eslintrc.json', + 'yarn.lock', + 'node_modules/next', + ] + + expect(res.exitCode).toBe(0) + projectFilesShouldExist({ cwd, projectName, files }) + }) +}) + +it('should infer yarn as the package manager with example', async () => { + try { + await execa('yarn', ['--version']) + } catch (_) { + // install yarn if not available + await execa('npm', ['i', '-g', 'yarn']) + } + + await useTempDir(async (cwd) => { + const projectName = 'infer-package-manager-npm' + const res = await run( + [ + projectName, + '--js', + '--no-tailwind', + '--eslint', + '--example', + `${exampleRepo}/${examplePath}`, + ], + { cwd, env: { ...process.env, npm_config_user_agent: 'yarn' } } + ) + + const files = [ + 'package.json', + 'pages/index.tsx', + '.gitignore', + 'yarn.lock', + 'node_modules/next', + ] + + expect(res.exitCode).toBe(0) + projectFilesShouldExist({ cwd, projectName, files }) + }) +}) + +it('should infer pnpm as the package manager', async () => { + try { + await execa('pnpm', ['--version']) + } catch (_) { + // install pnpm if not available + await execa('npm', ['i', '-g', 'pnpm']) + } + + await useTempDir(async (cwd) => { + const projectName = 'infer-package-manager' + const res = await run( + [ + projectName, + '--js', + '--no-tailwind', + '--eslint', + '--no-src-dir', + '--app', + `--import-alias=@/*`, + ], + { + cwd, + env: { ...process.env, npm_config_user_agent: 'pnpm' }, + } + ) + + const files = [ + 'package.json', + 'app/page.js', + '.gitignore', + '.eslintrc.json', + 'pnpm-lock.yaml', + 'node_modules/next', + ] + + expect(res.exitCode).toBe(0) + projectFilesShouldExist({ cwd, projectName, files }) + }) +}) + +it('should infer pnpm as the package manager with example', async () => { + try { + await execa('pnpm', ['--version']) + } catch (_) { + // install pnpm if not available + await execa('npm', ['i', '-g', 'pnpm']) + } + + await useTempDir(async (cwd) => { + const projectName = 'infer-package-manager-npm' + const res = await run( + [ + projectName, + '--js', + '--no-tailwind', + '--eslint', + '--example', + `${exampleRepo}/${examplePath}`, + ], + { cwd, env: { ...process.env, npm_config_user_agent: 'pnpm' } } + ) + + const files = [ + 'package.json', + 'pages/index.tsx', + '.gitignore', + 'pnpm-lock.yaml', + 'node_modules/next', + ] + + expect(res.exitCode).toBe(0) + projectFilesShouldExist({ cwd, projectName, files }) + }) +}) diff --git a/test/integration/create-next-app/templates-app.test.ts b/test/integration/create-next-app/templates-app.test.ts new file mode 100644 index 0000000000..b542890dee --- /dev/null +++ b/test/integration/create-next-app/templates-app.test.ts @@ -0,0 +1,196 @@ +/* eslint-env jest */ +/** + * @fileoverview + * + * This file contains tests for `create-next-app` templates, currently + * JavaScript (default), TypeScript, and appDir. + */ + +import path from 'path' +import fs from 'fs-extra' +import { + createNextApp, + shouldBeTemplateProject, + spawnExitPromise, +} from './lib/utils' +import { Span } from 'next/dist/trace' + +import { useTempDir } from '../../lib/use-temp-dir' +import { fetchViaHTTP, findPort, killApp, launchApp } from 'next-test-utils' +import resolveFrom from 'resolve-from' +import { createNextInstall } from '../../lib/create-next-install' + +const startsWithoutError = async ( + appDir: string, + modes = ['default', 'turbo'], + usingAppDirectory: boolean = false +) => { + for (const mode of modes) { + appDir = await fs.realpath(appDir) + const appPort = await findPort() + const app = await launchApp(appDir, appPort, { + turbo: mode === 'turbo', + cwd: appDir, + nextBin: resolveFrom(appDir, 'next/dist/bin/next'), + }) + + try { + const res = await fetchViaHTTP(appPort, '/') + expect(await res.text()).toContain('Get started by editing') + expect(res.status).toBe(200) + + if (!usingAppDirectory) { + const apiRes = await fetchViaHTTP(appPort, '/api/hello') + expect(await apiRes.json()).toEqual({ name: 'John Doe' }) + expect(apiRes.status).toBe(200) + } + } finally { + await killApp(app) + } + } +} +let testVersion + +describe('create-next-app --app', () => { + beforeAll(async () => { + if (testVersion) return + const span = new Span({ name: 'parent' }) + testVersion = ( + await createNextInstall({ onlyPackages: true, parentSpan: span }) + ).get('next') + }) + + it('should create TS appDir projects with --ts', async () => { + await useTempDir(async (cwd) => { + const projectName = 'appdir-test' + const childProcess = createNextApp( + [ + projectName, + '--ts', + '--no-tailwind', + '--app', + '--eslint', + '--no-src-dir', + `--import-alias=@/*`, + ], + { + cwd, + }, + testVersion + ) + + const exitCode = await spawnExitPromise(childProcess) + expect(exitCode).toBe(0) + shouldBeTemplateProject({ cwd, projectName, template: 'app', mode: 'ts' }) + await startsWithoutError( + path.join(cwd, projectName), + ['default', 'turbo'], + true + ) + }) + }) + + it('should create JS appDir projects with --js', async () => { + await useTempDir(async (cwd) => { + const projectName = 'appdir-test' + const childProcess = createNextApp( + [ + projectName, + '--js', + '--no-tailwind', + '--app', + '--eslint', + '--no-src-dir', + `--import-alias=@/*`, + ], + { + cwd, + }, + testVersion + ) + + const exitCode = await spawnExitPromise(childProcess) + expect(exitCode).toBe(0) + shouldBeTemplateProject({ cwd, projectName, template: 'app', mode: 'js' }) + // is landed + await startsWithoutError( + path.join(cwd, projectName), + ['default', 'turbo'], + true + ) + }) + }) + + it('should create JS appDir projects with --js --src-dir', async () => { + await useTempDir(async (cwd) => { + const projectName = 'appdir-test' + const childProcess = createNextApp( + [ + projectName, + '--js', + '--no-tailwind', + '--app', + '--eslint', + '--src-dir', + '--import-alias=@/*', + ], + { + cwd, + stdio: 'inherit', + }, + testVersion + ) + + const exitCode = await spawnExitPromise(childProcess) + expect(exitCode).toBe(0) + shouldBeTemplateProject({ + cwd, + projectName, + template: 'app', + mode: 'js', + srcDir: true, + }) + await startsWithoutError( + path.join(cwd, projectName), + ['default', 'turbo'], + true + ) + }) + }) + + it('should create Tailwind CSS appDir projects with --tailwind', async () => { + await useTempDir(async (cwd) => { + const projectName = 'appdir-tailwind-test' + const childProcess = createNextApp( + [ + projectName, + '--ts', + '--tailwind', + '--app', + '--eslint', + '--src-dir', + `--import-alias=@/*`, + ], + { + cwd, + }, + testVersion + ) + + const exitCode = await spawnExitPromise(childProcess) + expect(exitCode).toBe(0) + shouldBeTemplateProject({ + cwd, + projectName, + template: 'app-tw', + mode: 'ts', + srcDir: true, + }) + await startsWithoutError( + path.join(cwd, projectName), + ['default', 'turbo'], + true + ) + }) + }) +}) diff --git a/test/integration/create-next-app/templates.test.ts b/test/integration/create-next-app/templates-pages.test.ts similarity index 69% rename from test/integration/create-next-app/templates.test.ts rename to test/integration/create-next-app/templates-pages.test.ts index a56732d28b..d8b302f2c9 100644 --- a/test/integration/create-next-app/templates.test.ts +++ b/test/integration/create-next-app/templates-pages.test.ts @@ -12,13 +12,12 @@ import { createNextApp, projectFilesShouldExist, shouldBeJavascriptProject, - shouldBeTemplateProject, shouldBeTypescriptProject, spawnExitPromise, } from './lib/utils' import { Span } from 'next/dist/trace' -import { useTempDir } from '../../../test/lib/use-temp-dir' +import { useTempDir } from '../../lib/use-temp-dir' import { check, fetchViaHTTP, @@ -27,7 +26,7 @@ import { launchApp, } from 'next-test-utils' import resolveFrom from 'resolve-from' -import { createNextInstall } from '../../../test/lib/create-next-install' +import { createNextInstall } from '../../lib/create-next-install' import ansiEscapes from 'ansi-escapes' const startsWithoutError = async ( @@ -176,29 +175,6 @@ describe('create-next-app templates', () => { }) }) - it('should create TS projects with --ts, --typescript with CI=1', async () => { - await useTempDir(async (cwd) => { - const projectName = 'typescript-test' - const childProcess = createNextApp( - [projectName, '--ts', '--no-tailwind', '--eslint', '--app'], - { - cwd, - env: { - ...process.env, - CI: '1', - GITHUB_ACTIONS: '1', - }, - }, - testVersion - ) - const exitCode = await spawnExitPromise(childProcess) - - expect(exitCode).toBe(0) - shouldBeTypescriptProject({ cwd, projectName, template: 'app' }) - await startsWithoutError(path.join(cwd, projectName), undefined, true) - }) - }) - it('should create JS projects with --js, --javascript', async () => { await useTempDir(async (cwd) => { const projectName = 'javascript-test' @@ -414,147 +390,3 @@ describe('create-next-app templates', () => { }) }) }) - -describe('create-next-app --app', () => { - beforeAll(async () => { - if (testVersion) return - const span = new Span({ name: 'parent' }) - testVersion = ( - await createNextInstall({ onlyPackages: true, parentSpan: span }) - ).get('next') - }) - - it('should create TS appDir projects with --ts', async () => { - await useTempDir(async (cwd) => { - const projectName = 'appdir-test' - const childProcess = createNextApp( - [ - projectName, - '--ts', - '--no-tailwind', - '--app', - '--eslint', - '--no-src-dir', - `--import-alias=@/*`, - ], - { - cwd, - }, - testVersion - ) - - const exitCode = await spawnExitPromise(childProcess) - expect(exitCode).toBe(0) - shouldBeTemplateProject({ cwd, projectName, template: 'app', mode: 'ts' }) - await startsWithoutError( - path.join(cwd, projectName), - ['default', 'turbo'], - true - ) - }) - }) - - it('should create JS appDir projects with --js', async () => { - await useTempDir(async (cwd) => { - const projectName = 'appdir-test' - const childProcess = createNextApp( - [ - projectName, - '--js', - '--no-tailwind', - '--app', - '--eslint', - '--no-src-dir', - `--import-alias=@/*`, - ], - { - cwd, - }, - testVersion - ) - - const exitCode = await spawnExitPromise(childProcess) - expect(exitCode).toBe(0) - shouldBeTemplateProject({ cwd, projectName, template: 'app', mode: 'js' }) - // is landed - await startsWithoutError( - path.join(cwd, projectName), - ['default', 'turbo'], - true - ) - }) - }) - - it('should create JS appDir projects with --js --src-dir', async () => { - await useTempDir(async (cwd) => { - const projectName = 'appdir-test' - const childProcess = createNextApp( - [ - projectName, - '--js', - '--no-tailwind', - '--app', - '--eslint', - '--src-dir', - '--import-alias=@/*', - ], - { - cwd, - stdio: 'inherit', - }, - testVersion - ) - - const exitCode = await spawnExitPromise(childProcess) - expect(exitCode).toBe(0) - shouldBeTemplateProject({ - cwd, - projectName, - template: 'app', - mode: 'js', - srcDir: true, - }) - await startsWithoutError( - path.join(cwd, projectName), - ['default', 'turbo'], - true - ) - }) - }) - - it('should create Tailwind CSS appDir projects with --tailwind', async () => { - await useTempDir(async (cwd) => { - const projectName = 'appdir-tailwind-test' - const childProcess = createNextApp( - [ - projectName, - '--ts', - '--tailwind', - '--app', - '--eslint', - '--src-dir', - `--import-alias=@/*`, - ], - { - cwd, - }, - testVersion - ) - - const exitCode = await spawnExitPromise(childProcess) - expect(exitCode).toBe(0) - shouldBeTemplateProject({ - cwd, - projectName, - template: 'app-tw', - mode: 'ts', - srcDir: true, - }) - await startsWithoutError( - path.join(cwd, projectName), - ['default', 'turbo'], - true - ) - }) - }) -}) diff --git a/test/integration/css-features/test/browserslist.test.js b/test/integration/css-features/test/browserslist.test.js new file mode 100644 index 0000000000..2fbf1d1190 --- /dev/null +++ b/test/integration/css-features/test/browserslist.test.js @@ -0,0 +1,71 @@ +/* eslint-env jest */ + +import { readdir, readFile, remove } from 'fs-extra' +import { nextBuild } from 'next-test-utils' +import { join } from 'path' + +const fixturesDir = join(__dirname, '../fixtures') + +describe('Browserslist: Old', () => { + const appDir = join(fixturesDir, 'browsers-old') + + let stdout + let code + beforeAll(async () => { + await remove(join(appDir, '.next')) + ;({ code, stdout } = await nextBuild(appDir, [], { + stdout: true, + })) + }) + + it('should have compiled successfully', () => { + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it(`should've emitted a single CSS file`, async () => { + const cssFolder = join(appDir, '.next/static/css') + + const files = await readdir(cssFolder) + const cssFiles = files.filter((f) => /\.css$/.test(f)) + + expect(cssFiles.length).toBe(1) + const cssContent = await readFile(join(cssFolder, cssFiles[0]), 'utf8') + + expect(cssContent.replace(/\/\*.*?\*\//g, '').trim()).toMatchInlineSnapshot( + `"a{-webkit-animation:none 0s ease 0s 1 normal none running;animation:none 0s ease 0s 1 normal none running;-webkit-backface-visibility:visible;backface-visibility:visible;background:transparent none repeat 0 0/auto auto padding-box border-box scroll;border:none;border-collapse:separate;-webkit-border-image:none;border-image:none;-webkit-border-radius:0;border-radius:0;border-spacing:0;bottom:auto;-webkit-box-shadow:none;box-shadow:none;-webkit-box-sizing:content-box;box-sizing:content-box;caption-side:top;clear:none;clip:auto;color:#000;-webkit-columns:auto;-webkit-column-count:auto;-webkit-column-fill:balance;column-fill:balance;-webkit-column-gap:normal;column-gap:normal;-webkit-column-rule:medium none currentColor;column-rule:medium none currentColor;-webkit-column-span:1;column-span:1;-webkit-column-width:auto;columns:auto;content:normal;counter-increment:none;counter-reset:none;cursor:auto;direction:ltr;display:inline;empty-cells:show;float:none;font-family:serif;font-size:medium;font-style:normal;font-variant:normal;font-weight:400;font-stretch:normal;line-height:normal;height:auto;-ms-hyphens:none;hyphens:none;left:auto;letter-spacing:normal;list-style:disc none outside;margin:0;max-height:none;max-width:none;min-height:0;min-width:0;opacity:1;orphans:2;outline:medium none invert;overflow:visible;overflow-x:visible;overflow-y:visible;padding:0;page-break-after:auto;page-break-before:auto;page-break-inside:auto;-webkit-perspective:none;perspective:none;-webkit-perspective-origin:50% 50%;perspective-origin:50% 50%;position:static;right:auto;tab-size:8;table-layout:auto;text-align:left;text-align-last:auto;text-decoration:none;text-indent:0;text-shadow:none;text-transform:none;top:auto;-webkit-transform:none;transform:none;-webkit-transform-origin:50% 50% 0;transform-origin:50% 50% 0;-webkit-transform-style:flat;transform-style:flat;-webkit-transition:none 0s ease 0s;transition:none 0s ease 0s;unicode-bidi:normal;vertical-align:baseline;visibility:visible;white-space:normal;widows:2;width:auto;word-spacing:normal;z-index:auto;all:initial}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){.image{background-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==)}}"` + ) + }) +}) + +describe('Browserslist: New', () => { + const appDir = join(fixturesDir, 'browsers-new') + + let stdout + let code + beforeAll(async () => { + await remove(join(appDir, '.next')) + ;({ code, stdout } = await nextBuild(appDir, [], { + stdout: true, + })) + }) + + it('should have compiled successfully', () => { + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it(`should've emitted a single CSS file`, async () => { + const cssFolder = join(appDir, '.next/static/css') + + const files = await readdir(cssFolder) + const cssFiles = files.filter((f) => /\.css$/.test(f)) + + expect(cssFiles.length).toBe(1) + const cssContent = await readFile(join(cssFolder, cssFiles[0]), 'utf8') + + expect(cssContent.replace(/\/\*.*?\*\//g, '').trim()).toMatchInlineSnapshot( + `"a{all:initial}@media (min-resolution:2dppx){.image{background-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==)}}"` + ) + }) +}) diff --git a/test/integration/css-features/test/css-modules.test.js b/test/integration/css-features/test/css-modules.test.js new file mode 100644 index 0000000000..3def62504e --- /dev/null +++ b/test/integration/css-features/test/css-modules.test.js @@ -0,0 +1,125 @@ +/* eslint-env jest */ + +import { readdir, readFile, remove } from 'fs-extra' +import { nextBuild } from 'next-test-utils' +import { join } from 'path' + +const fixturesDir = join(__dirname, '../fixtures') + +describe('Custom Properties: Fail for :root {} in CSS Modules', () => { + const appDir = join(fixturesDir, 'cp-global-modules') + + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + + it('should fail to build', async () => { + const { code, stderr } = await nextBuild(appDir, [], { + stderr: true, + }) + expect(code).not.toBe(0) + expect(stderr).toContain('Failed to compile') + expect(stderr).toContain('pages/styles.module.css') + expect(stderr).toContain('Selector ":root" is not pure') + }) +}) + +describe('Custom Properties: Fail for global element in CSS Modules', () => { + const appDir = join(fixturesDir, 'cp-el-modules') + + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + + it('should fail to build', async () => { + const { code, stderr } = await nextBuild(appDir, [], { + stderr: true, + }) + expect(code).not.toBe(0) + expect(stderr).toContain('Failed to compile') + expect(stderr).toContain('pages/styles.module.css') + expect(stderr).toContain('Selector "h1" is not pure') + }) +}) + +describe('CSS Modules: Import Global CSS', () => { + const appDir = join(fixturesDir, 'module-import-global') + + let stdout + let code + beforeAll(async () => { + await remove(join(appDir, '.next')) + ;({ code, stdout } = await nextBuild(appDir, [], { + stdout: true, + })) + }) + + it('should have compiled successfully', () => { + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it(`should've emitted a single CSS file`, async () => { + const cssFolder = join(appDir, '.next/static/css') + + const files = await readdir(cssFolder) + const cssFiles = files.filter((f) => /\.css$/.test(f)) + + expect(cssFiles.length).toBe(1) + const cssContent = await readFile(join(cssFolder, cssFiles[0]), 'utf8') + + expect(cssContent.replace(/\/\*.*?\*\//g, '').trim()).toMatchInlineSnapshot( + `"a .styles_foo__Io_Us{all:initial}"` + ) + }) +}) + +describe('CSS Modules: Importing Invalid Global CSS', () => { + const appDir = join(fixturesDir, 'module-import-global-invalid') + + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + + it('should fail to build', async () => { + const { code, stderr } = await nextBuild(appDir, [], { + stderr: true, + }) + expect(code).not.toBe(0) + expect(stderr).toContain('Failed to compile') + expect(stderr).toContain('pages/styles.css') + expect(stderr).toContain('Selector "a" is not pure') + }) +}) + +describe('CSS Modules: Import Exports', () => { + const appDir = join(fixturesDir, 'module-import-exports') + + let stdout + let code + beforeAll(async () => { + await remove(join(appDir, '.next')) + ;({ code, stdout } = await nextBuild(appDir, [], { + stdout: true, + })) + }) + + it('should have compiled successfully', () => { + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it(`should've emitted a single CSS file`, async () => { + const cssFolder = join(appDir, '.next/static/css') + + const files = await readdir(cssFolder) + const cssFiles = files.filter((f) => /\.css$/.test(f)) + + expect(cssFiles.length).toBe(1) + const cssContent = await readFile(join(cssFolder, cssFiles[0]), 'utf8') + + expect(cssContent.replace(/\/\*.*?\*\//g, '').trim()).toMatchInlineSnapshot( + `".styles_blk__CqbFg{color:#000}"` + ) + }) +}) diff --git a/test/integration/css-features/test/index.test.js b/test/integration/css-features/test/index.test.js index e2228031f4..d7eb6b0e73 100644 --- a/test/integration/css-features/test/index.test.js +++ b/test/integration/css-features/test/index.test.js @@ -6,70 +6,6 @@ import { join } from 'path' const fixturesDir = join(__dirname, '../fixtures') -describe('Browserslist: Old', () => { - const appDir = join(fixturesDir, 'browsers-old') - - let stdout - let code - beforeAll(async () => { - await remove(join(appDir, '.next')) - ;({ code, stdout } = await nextBuild(appDir, [], { - stdout: true, - })) - }) - - it('should have compiled successfully', () => { - expect(code).toBe(0) - expect(stdout).toMatch(/Compiled successfully/) - }) - - it(`should've emitted a single CSS file`, async () => { - const cssFolder = join(appDir, '.next/static/css') - - const files = await readdir(cssFolder) - const cssFiles = files.filter((f) => /\.css$/.test(f)) - - expect(cssFiles.length).toBe(1) - const cssContent = await readFile(join(cssFolder, cssFiles[0]), 'utf8') - - expect(cssContent.replace(/\/\*.*?\*\//g, '').trim()).toMatchInlineSnapshot( - `"a{-webkit-animation:none 0s ease 0s 1 normal none running;animation:none 0s ease 0s 1 normal none running;-webkit-backface-visibility:visible;backface-visibility:visible;background:transparent none repeat 0 0/auto auto padding-box border-box scroll;border:none;border-collapse:separate;-webkit-border-image:none;border-image:none;-webkit-border-radius:0;border-radius:0;border-spacing:0;bottom:auto;-webkit-box-shadow:none;box-shadow:none;-webkit-box-sizing:content-box;box-sizing:content-box;caption-side:top;clear:none;clip:auto;color:#000;-webkit-columns:auto;-webkit-column-count:auto;-webkit-column-fill:balance;column-fill:balance;-webkit-column-gap:normal;column-gap:normal;-webkit-column-rule:medium none currentColor;column-rule:medium none currentColor;-webkit-column-span:1;column-span:1;-webkit-column-width:auto;columns:auto;content:normal;counter-increment:none;counter-reset:none;cursor:auto;direction:ltr;display:inline;empty-cells:show;float:none;font-family:serif;font-size:medium;font-style:normal;font-variant:normal;font-weight:400;font-stretch:normal;line-height:normal;height:auto;-ms-hyphens:none;hyphens:none;left:auto;letter-spacing:normal;list-style:disc none outside;margin:0;max-height:none;max-width:none;min-height:0;min-width:0;opacity:1;orphans:2;outline:medium none invert;overflow:visible;overflow-x:visible;overflow-y:visible;padding:0;page-break-after:auto;page-break-before:auto;page-break-inside:auto;-webkit-perspective:none;perspective:none;-webkit-perspective-origin:50% 50%;perspective-origin:50% 50%;position:static;right:auto;tab-size:8;table-layout:auto;text-align:left;text-align-last:auto;text-decoration:none;text-indent:0;text-shadow:none;text-transform:none;top:auto;-webkit-transform:none;transform:none;-webkit-transform-origin:50% 50% 0;transform-origin:50% 50% 0;-webkit-transform-style:flat;transform-style:flat;-webkit-transition:none 0s ease 0s;transition:none 0s ease 0s;unicode-bidi:normal;vertical-align:baseline;visibility:visible;white-space:normal;widows:2;width:auto;word-spacing:normal;z-index:auto;all:initial}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){.image{background-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==)}}"` - ) - }) -}) - -describe('Browserslist: New', () => { - const appDir = join(fixturesDir, 'browsers-new') - - let stdout - let code - beforeAll(async () => { - await remove(join(appDir, '.next')) - ;({ code, stdout } = await nextBuild(appDir, [], { - stdout: true, - })) - }) - - it('should have compiled successfully', () => { - expect(code).toBe(0) - expect(stdout).toMatch(/Compiled successfully/) - }) - - it(`should've emitted a single CSS file`, async () => { - const cssFolder = join(appDir, '.next/static/css') - - const files = await readdir(cssFolder) - const cssFiles = files.filter((f) => /\.css$/.test(f)) - - expect(cssFiles.length).toBe(1) - const cssContent = await readFile(join(cssFolder, cssFiles[0]), 'utf8') - - expect(cssContent.replace(/\/\*.*?\*\//g, '').trim()).toMatchInlineSnapshot( - `"a{all:initial}@media (min-resolution:2dppx){.image{background-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==)}}"` - ) - }) -}) - describe('Custom Properties: Pass-Through IE11', () => { const appDir = join(fixturesDir, 'cp-ie-11') @@ -134,124 +70,6 @@ describe('Custom Properties: Pass-Through Modern', () => { }) }) -describe('Custom Properties: Fail for :root {} in CSS Modules', () => { - const appDir = join(fixturesDir, 'cp-global-modules') - - beforeAll(async () => { - await remove(join(appDir, '.next')) - }) - - it('should fail to build', async () => { - const { code, stderr } = await nextBuild(appDir, [], { - stderr: true, - }) - expect(code).not.toBe(0) - expect(stderr).toContain('Failed to compile') - expect(stderr).toContain('pages/styles.module.css') - expect(stderr).toContain('Selector ":root" is not pure') - }) -}) - -describe('Custom Properties: Fail for global element in CSS Modules', () => { - const appDir = join(fixturesDir, 'cp-el-modules') - - beforeAll(async () => { - await remove(join(appDir, '.next')) - }) - - it('should fail to build', async () => { - const { code, stderr } = await nextBuild(appDir, [], { - stderr: true, - }) - expect(code).not.toBe(0) - expect(stderr).toContain('Failed to compile') - expect(stderr).toContain('pages/styles.module.css') - expect(stderr).toContain('Selector "h1" is not pure') - }) -}) - -describe('CSS Modules: Import Global CSS', () => { - const appDir = join(fixturesDir, 'module-import-global') - - let stdout - let code - beforeAll(async () => { - await remove(join(appDir, '.next')) - ;({ code, stdout } = await nextBuild(appDir, [], { - stdout: true, - })) - }) - - it('should have compiled successfully', () => { - expect(code).toBe(0) - expect(stdout).toMatch(/Compiled successfully/) - }) - - it(`should've emitted a single CSS file`, async () => { - const cssFolder = join(appDir, '.next/static/css') - - const files = await readdir(cssFolder) - const cssFiles = files.filter((f) => /\.css$/.test(f)) - - expect(cssFiles.length).toBe(1) - const cssContent = await readFile(join(cssFolder, cssFiles[0]), 'utf8') - - expect(cssContent.replace(/\/\*.*?\*\//g, '').trim()).toMatchInlineSnapshot( - `"a .styles_foo__Io_Us{all:initial}"` - ) - }) -}) - -describe('CSS Modules: Importing Invalid Global CSS', () => { - const appDir = join(fixturesDir, 'module-import-global-invalid') - - beforeAll(async () => { - await remove(join(appDir, '.next')) - }) - - it('should fail to build', async () => { - const { code, stderr } = await nextBuild(appDir, [], { - stderr: true, - }) - expect(code).not.toBe(0) - expect(stderr).toContain('Failed to compile') - expect(stderr).toContain('pages/styles.css') - expect(stderr).toContain('Selector "a" is not pure') - }) -}) - -describe('CSS Modules: Import Exports', () => { - const appDir = join(fixturesDir, 'module-import-exports') - - let stdout - let code - beforeAll(async () => { - await remove(join(appDir, '.next')) - ;({ code, stdout } = await nextBuild(appDir, [], { - stdout: true, - })) - }) - - it('should have compiled successfully', () => { - expect(code).toBe(0) - expect(stdout).toMatch(/Compiled successfully/) - }) - - it(`should've emitted a single CSS file`, async () => { - const cssFolder = join(appDir, '.next/static/css') - - const files = await readdir(cssFolder) - const cssFiles = files.filter((f) => /\.css$/.test(f)) - - expect(cssFiles.length).toBe(1) - const cssContent = await readFile(join(cssFolder, cssFiles[0]), 'utf8') - - expect(cssContent.replace(/\/\*.*?\*\//g, '').trim()).toMatchInlineSnapshot( - `".styles_blk__CqbFg{color:#000}"` - ) - }) -}) - describe('Inline Comments: Minify', () => { const appDir = join(fixturesDir, 'inline-comments') diff --git a/test/integration/css/test/basic-global-support.test.js b/test/integration/css/test/basic-global-support.test.js new file mode 100644 index 0000000000..e956947422 --- /dev/null +++ b/test/integration/css/test/basic-global-support.test.js @@ -0,0 +1,317 @@ +/* eslint-env jest */ +import 'flat-map-polyfill' +import { readdir, readFile, remove } from 'fs-extra' +import { nextBuild } from 'next-test-utils' +import { join } from 'path' + +const fixturesDir = join(__dirname, '../..', 'css-fixtures') + +describe('Basic Global Support', () => { + const appDir = join(fixturesDir, 'single-global') + + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + + it('should compile successfully', async () => { + const { code, stdout } = await nextBuild(appDir, [], { + stdout: true, + }) + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it(`should've emitted a single CSS file`, async () => { + const cssFolder = join(appDir, '.next/static/css') + + const files = await readdir(cssFolder) + const cssFiles = files.filter((f) => /\.css$/.test(f)) + + expect(cssFiles.length).toBe(1) + expect(await readFile(join(cssFolder, cssFiles[0]), 'utf8')).toContain( + 'color:red' + ) + }) +}) + +describe('Basic Global Support with special characters in path', () => { + const appDir = join(fixturesDir, 'single-global-special-characters', 'a+b') + + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + + it('should compile successfully', async () => { + const { code, stdout } = await nextBuild(appDir, [], { + stdout: true, + }) + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it(`should've emitted a single CSS file`, async () => { + const cssFolder = join(appDir, '.next/static/css') + + const files = await readdir(cssFolder) + const cssFiles = files.filter((f) => /\.css$/.test(f)) + + expect(cssFiles.length).toBe(1) + expect(await readFile(join(cssFolder, cssFiles[0]), 'utf8')).toContain( + 'color:red' + ) + }) +}) + +describe('Basic Global Support with src/ dir', () => { + const appDir = join(fixturesDir, 'single-global-src') + + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + + it('should compile successfully', async () => { + const { code, stdout } = await nextBuild(appDir, [], { + stdout: true, + }) + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it(`should've emitted a single CSS file`, async () => { + const cssFolder = join(appDir, '.next/static/css') + + const files = await readdir(cssFolder) + const cssFiles = files.filter((f) => /\.css$/.test(f)) + + expect(cssFiles.length).toBe(1) + expect(await readFile(join(cssFolder, cssFiles[0]), 'utf8')).toContain( + 'color:red' + ) + }) +}) + +describe('Multi Global Support', () => { + const appDir = join(fixturesDir, 'multi-global') + + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + + it('should compile successfully', async () => { + const { code, stdout } = await nextBuild(appDir, [], { + stdout: true, + }) + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it(`should've emitted a single CSS file`, async () => { + const cssFolder = join(appDir, '.next/static/css') + + const files = await readdir(cssFolder) + const cssFiles = files.filter((f) => /\.css$/.test(f)) + + expect(cssFiles.length).toBe(1) + const cssContent = await readFile(join(cssFolder, cssFiles[0]), 'utf8') + expect(cssContent.replace(/\/\*.*?\*\//g, '').trim()).toMatchInlineSnapshot( + `".red-text{color:red}.blue-text{color:blue}"` + ) + }) +}) + +describe('Nested @import() Global Support', () => { + const appDir = join(fixturesDir, 'nested-global') + + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + + it('should compile successfully', async () => { + const { code, stdout } = await nextBuild(appDir, [], { + stdout: true, + }) + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it(`should've emitted a single CSS file`, async () => { + const cssFolder = join(appDir, '.next/static/css') + + const files = await readdir(cssFolder) + const cssFiles = files.filter((f) => /\.css$/.test(f)) + + expect(cssFiles.length).toBe(1) + const cssContent = await readFile(join(cssFolder, cssFiles[0]), 'utf8') + expect(cssContent.replace(/\/\*.*?\*\//g, '').trim()).toMatchInlineSnapshot( + `".red-text{color:purple;font-weight:bolder;color:red}.blue-text{color:orange;font-weight:bolder;color:blue}"` + ) + }) +}) + +// Tests css ordering +describe('Multi Global Support (reversed)', () => { + const appDir = join(fixturesDir, 'multi-global-reversed') + + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + + it('should compile successfully', async () => { + const { code, stdout } = await nextBuild(appDir, [], { + stdout: true, + }) + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it(`should've emitted a single CSS file`, async () => { + const cssFolder = join(appDir, '.next/static/css') + + const files = await readdir(cssFolder) + const cssFiles = files.filter((f) => /\.css$/.test(f)) + + expect(cssFiles.length).toBe(1) + const cssContent = await readFile(join(cssFolder, cssFiles[0]), 'utf8') + expect(cssContent.replace(/\/\*.*?\*\//g, '').trim()).toMatchInlineSnapshot( + `".blue-text{color:blue}.red-text{color:red}"` + ) + }) +}) + +describe('CSS URL via `file-loader`', () => { + const appDir = join(fixturesDir, 'url-global') + + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + + it('should compile successfully', async () => { + const { code, stdout } = await nextBuild(appDir, [], { + stdout: true, + }) + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it(`should've emitted expected files`, async () => { + const cssFolder = join(appDir, '.next/static/css') + const mediaFolder = join(appDir, '.next/static/media') + + const files = await readdir(cssFolder) + const cssFiles = files.filter((f) => /\.css$/.test(f)) + + expect(cssFiles.length).toBe(1) + const cssContent = await readFile(join(cssFolder, cssFiles[0]), 'utf8') + expect(cssContent.replace(/\/\*.*?\*\//g, '').trim()).toMatch( + /^\.red-text\{color:red;background-image:url\(\/_next\/static\/media\/dark\.[a-f0-9]{8}\.svg\) url\(\/_next\/static\/media\/dark2\.[a-f0-9]{8}\.svg\)\}\.blue-text\{color:orange;font-weight:bolder;background-image:url\(\/_next\/static\/media\/light\.[a-f0-9]{8}\.svg\);color:blue\}$/ + ) + + const mediaFiles = await readdir(mediaFolder) + expect(mediaFiles.length).toBe(3) + expect( + mediaFiles + .map((fileName) => + /^(.+?)\..{8}\.(.+?)$/.exec(fileName).slice(1).join('.') + ) + .sort() + ).toMatchInlineSnapshot(` + Array [ + "dark.svg", + "dark2.svg", + "light.svg", + ] + `) + }) +}) + +describe('CSS URL via `file-loader` and asset prefix (1)', () => { + const appDir = join(fixturesDir, 'url-global-asset-prefix-1') + + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + + it('should compile successfully', async () => { + const { code, stdout } = await nextBuild(appDir, [], { + stdout: true, + }) + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it(`should've emitted expected files`, async () => { + const cssFolder = join(appDir, '.next/static/css') + const mediaFolder = join(appDir, '.next/static/media') + + const files = await readdir(cssFolder) + const cssFiles = files.filter((f) => /\.css$/.test(f)) + + expect(cssFiles.length).toBe(1) + const cssContent = await readFile(join(cssFolder, cssFiles[0]), 'utf8') + expect(cssContent.replace(/\/\*.*?\*\//g, '').trim()).toMatch( + /^\.red-text\{color:red;background-image:url\(\/foo\/_next\/static\/media\/dark\.[a-f0-9]{8}\.svg\) url\(\/foo\/_next\/static\/media\/dark2\.[a-f0-9]{8}\.svg\)\}\.blue-text\{color:orange;font-weight:bolder;background-image:url\(\/foo\/_next\/static\/media\/light\.[a-f0-9]{8}\.svg\);color:blue\}$/ + ) + + const mediaFiles = await readdir(mediaFolder) + expect(mediaFiles.length).toBe(3) + expect( + mediaFiles + .map((fileName) => + /^(.+?)\..{8}\.(.+?)$/.exec(fileName).slice(1).join('.') + ) + .sort() + ).toMatchInlineSnapshot(` + Array [ + "dark.svg", + "dark2.svg", + "light.svg", + ] + `) + }) +}) + +describe('CSS URL via `file-loader` and asset prefix (2)', () => { + const appDir = join(fixturesDir, 'url-global-asset-prefix-2') + + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + + it('should compile successfully', async () => { + const { code, stdout } = await nextBuild(appDir, [], { + stdout: true, + }) + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it(`should've emitted expected files`, async () => { + const cssFolder = join(appDir, '.next/static/css') + const mediaFolder = join(appDir, '.next/static/media') + + const files = await readdir(cssFolder) + const cssFiles = files.filter((f) => /\.css$/.test(f)) + + expect(cssFiles.length).toBe(1) + const cssContent = await readFile(join(cssFolder, cssFiles[0]), 'utf8') + expect(cssContent.replace(/\/\*.*?\*\//g, '').trim()).toMatch( + /^\.red-text\{color:red;background-image:url\(\/foo\/_next\/static\/media\/dark\.[a-f0-9]{8}\.svg\) url\(\/foo\/_next\/static\/media\/dark2\.[a-f0-9]{8}\.svg\)\}\.blue-text\{color:orange;font-weight:bolder;background-image:url\(\/foo\/_next\/static\/media\/light\.[a-f0-9]{8}\.svg\);color:blue\}$/ + ) + + const mediaFiles = await readdir(mediaFolder) + expect(mediaFiles.length).toBe(3) + expect( + mediaFiles + .map((fileName) => + /^(.+?)\..{8}\.(.+?)$/.exec(fileName).slice(1).join('.') + ) + .sort() + ).toMatchInlineSnapshot(` + Array [ + "dark.svg", + "dark2.svg", + "light.svg", + ] + `) + }) +}) diff --git a/test/integration/css/test/css-and-styled-jsx.test.js b/test/integration/css/test/css-and-styled-jsx.test.js new file mode 100644 index 0000000000..bc9d892803 --- /dev/null +++ b/test/integration/css/test/css-and-styled-jsx.test.js @@ -0,0 +1,72 @@ +/* eslint-env jest */ +import 'flat-map-polyfill' +import { remove } from 'fs-extra' +import { + findPort, + killApp, + launchApp, + nextBuild, + nextStart, +} from 'next-test-utils' +import webdriver from 'next-webdriver' +import { join } from 'path' + +const fixturesDir = join(__dirname, '../..', 'css-fixtures') + +describe('Ordering with styled-jsx (dev)', () => { + const appDir = join(fixturesDir, 'with-styled-jsx') + + let appPort + let app + beforeAll(async () => { + await remove(join(appDir, '.next')) + appPort = await findPort() + app = await launchApp(appDir, appPort) + }) + afterAll(async () => { + await killApp(app) + }) + + it('should have the correct color (css ordering)', async () => { + const browser = await webdriver(appPort, '/') + + const currentColor = await browser.eval( + `window.getComputedStyle(document.querySelector('.my-text')).color` + ) + expect(currentColor).toMatchInlineSnapshot(`"rgb(0, 128, 0)"`) + }) +}) + +describe('Ordering with styled-jsx (prod)', () => { + const appDir = join(fixturesDir, 'with-styled-jsx') + + let appPort + let app + let stdout + let code + beforeAll(async () => { + await remove(join(appDir, '.next')) + ;({ code, stdout } = await nextBuild(appDir, [], { + stdout: true, + })) + appPort = await findPort() + app = await nextStart(appDir, appPort) + }) + afterAll(async () => { + await killApp(app) + }) + + it('should have compiled successfully', () => { + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it('should have the correct color (css ordering)', async () => { + const browser = await webdriver(appPort, '/') + + const currentColor = await browser.eval( + `window.getComputedStyle(document.querySelector('.my-text')).color` + ) + expect(currentColor).toMatchInlineSnapshot(`"rgb(0, 128, 0)"`) + }) +}) diff --git a/test/integration/css/test/css-compilation.test.js b/test/integration/css/test/css-compilation.test.js new file mode 100644 index 0000000000..43293d3cd1 --- /dev/null +++ b/test/integration/css/test/css-compilation.test.js @@ -0,0 +1,288 @@ +/* eslint-env jest */ +import cheerio from 'cheerio' +import 'flat-map-polyfill' +import { readdir, readFile, remove } from 'fs-extra' +import { + findPort, + killApp, + nextBuild, + nextStart, + renderViaHTTP, +} from 'next-test-utils' +import webdriver from 'next-webdriver' +import { join } from 'path' + +const fixturesDir = join(__dirname, '../..', 'css-fixtures') + +describe('CSS Support', () => { + describe('CSS Compilation and Prefixing', () => { + const appDir = join(fixturesDir, 'compilation-and-prefixing') + + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + + it('should compile successfully', async () => { + const { code, stdout } = await nextBuild(appDir, [], { + stdout: true, + }) + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it(`should've compiled and prefixed`, async () => { + const cssFolder = join(appDir, '.next/static/css') + + const files = await readdir(cssFolder) + const cssFiles = files.filter((f) => /\.css$/.test(f)) + + expect(cssFiles.length).toBe(1) + const cssContent = await readFile(join(cssFolder, cssFiles[0]), 'utf8') + expect( + cssContent.replace(/\/\*.*?\*\//g, '').trim() + ).toMatchInlineSnapshot( + `"@media (min-width:480px) and (max-width:767px){::placeholder{color:green}}.flex-parsing{flex:0 0 calc(50% - var(--vertical-gutter))}.transform-parsing{transform:translate3d(0,0)}.css-grid-shorthand{grid-column:span 2}.g-docs-sidenav .filter::-webkit-input-placeholder{opacity:80%}"` + ) + + // Contains a source map + expect(cssContent).toMatch(/\/\*#\s*sourceMappingURL=(.+\.map)\s*\*\//) + }) + + it(`should've emitted a source map`, async () => { + const cssFolder = join(appDir, '.next/static/css') + + const files = await readdir(cssFolder) + const cssMapFiles = files.filter((f) => /\.css\.map$/.test(f)) + + expect(cssMapFiles.length).toBe(1) + const cssMapContent = ( + await readFile(join(cssFolder, cssMapFiles[0]), 'utf8') + ).trim() + + const { version, mappings, sourcesContent } = JSON.parse(cssMapContent) + expect({ version, mappings, sourcesContent }).toMatchInlineSnapshot(` + Object { + "mappings": "AAAA,+CACE,cACE,WACF,CACF,CAEA,cACE,2CACF,CAEA,mBACE,0BACF,CAEA,oBACE,kBACF,CAEA,mDACE,WACF", + "sourcesContent": Array [ + "@media (480px <= width < 768px) { + ::placeholder { + color: green; + } + } + + .flex-parsing { + flex: 0 0 calc(50% - var(--vertical-gutter)); + } + + .transform-parsing { + transform: translate3d(0px, 0px); + } + + .css-grid-shorthand { + grid-column: span 2; + } + + .g-docs-sidenav .filter::-webkit-input-placeholder { + opacity: 80%; + } + ", + ], + "version": 3, + } + `) + }) + }) + + describe('React Lifecyce Order (production)', () => { + const appDir = join(fixturesDir, 'transition-react') + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + + let appPort + let app + let code + let stdout + beforeAll(async () => { + ;({ code, stdout } = await nextBuild(appDir, [], { + stdout: true, + })) + appPort = await findPort() + app = await nextStart(appDir, appPort) + }) + afterAll(async () => { + await killApp(app) + }) + + it('should have compiled successfully', () => { + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it('should have the correct color on mount after navigation', async () => { + let browser + try { + browser = await webdriver(appPort, '/') + + // Navigate to other: + await browser.waitForElementByCss('#link-other').click() + const text = await browser.waitForElementByCss('#red-title').text() + expect(text).toMatchInlineSnapshot(`"rgb(255, 0, 0)"`) + } finally { + if (browser) { + await browser.close() + } + } + }) + }) + + describe('Has CSS in computed styles in Production', () => { + const appDir = join(fixturesDir, 'multi-page') + + let appPort + let app + let stdout + let code + beforeAll(async () => { + await remove(join(appDir, '.next')) + ;({ code, stdout } = await nextBuild(appDir, [], { + stdout: true, + })) + appPort = await findPort() + app = await nextStart(appDir, appPort) + }) + afterAll(async () => { + await killApp(app) + }) + + it('should have compiled successfully', () => { + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it('should have CSS for page', async () => { + const browser = await webdriver(appPort, '/page2') + + const currentColor = await browser.eval( + `window.getComputedStyle(document.querySelector('.blue-text')).color` + ) + expect(currentColor).toMatchInlineSnapshot(`"rgb(0, 0, 255)"`) + }) + + it(`should've preloaded the CSS file and injected it in `, async () => { + const content = await renderViaHTTP(appPort, '/page2') + const $ = cheerio.load(content) + + const cssPreload = $('link[rel="preload"][as="style"]') + expect(cssPreload.length).toBe(1) + expect(cssPreload.attr('href')).toMatch(/^\/_next\/static\/css\/.*\.css$/) + + const cssSheet = $('link[rel="stylesheet"]') + expect(cssSheet.length).toBe(1) + expect(cssSheet.attr('href')).toMatch(/^\/_next\/static\/css\/.*\.css$/) + + /* ensure CSS preloaded first */ + const allPreloads = [].slice.call($('link[rel="preload"]')) + const styleIndexes = allPreloads.flatMap((p, i) => + p.attribs.as === 'style' ? i : [] + ) + expect(styleIndexes).toEqual([0]) + }) + }) + + describe('Good CSS Import from node_modules', () => { + const appDir = join(fixturesDir, 'npm-import') + + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + + it('should compile successfully', async () => { + const { code, stdout } = await nextBuild(appDir, [], { + stdout: true, + }) + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it(`should've emitted a single CSS file`, async () => { + const cssFolder = join(appDir, '.next/static/css') + + const files = await readdir(cssFolder) + const cssFiles = files.filter((f) => /\.css$/.test(f)) + + expect(cssFiles.length).toBe(1) + const cssContent = await readFile(join(cssFolder, cssFiles[0]), 'utf8') + expect(cssContent.replace(/\/\*.*?\*\//g, '').trim()).toMatch(/nprogress/) + }) + }) + + describe('Good Nested CSS Import from node_modules', () => { + const appDir = join(fixturesDir, 'npm-import-nested') + + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + + it('should compile successfully', async () => { + const { code, stdout } = await nextBuild(appDir, [], { + stdout: true, + }) + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it(`should've emitted a single CSS file`, async () => { + const cssFolder = join(appDir, '.next/static/css') + + const files = await readdir(cssFolder) + const cssFiles = files.filter((f) => /\.css$/.test(f)) + + expect(cssFiles.length).toBe(1) + const cssContent = await readFile(join(cssFolder, cssFiles[0]), 'utf8') + expect( + cssContent.replace(/\/\*.*?\*\//g, '').trim() + ).toMatchInlineSnapshot(`".other{color:blue}.test{color:red}"`) + }) + }) +}) + +// https://github.com/vercel/next.js/issues/15468 +describe('CSS Property Ordering', () => { + const appDir = join(fixturesDir, 'next-issue-15468') + + let appPort + let app + let stdout + let code + beforeAll(async () => { + await remove(join(appDir, '.next')) + ;({ code, stdout } = await nextBuild(appDir, [], { + stdout: true, + })) + appPort = await findPort() + app = await nextStart(appDir, appPort) + }) + afterAll(async () => { + await killApp(app) + }) + + it('should have compiled successfully', () => { + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it('should have the border width (property ordering)', async () => { + const browser = await webdriver(appPort, '/') + + const width1 = await browser.eval( + `window.getComputedStyle(document.querySelector('.test1')).borderWidth` + ) + expect(width1).toMatchInlineSnapshot(`"0px"`) + + const width2 = await browser.eval( + `window.getComputedStyle(document.querySelector('.test2')).borderWidth` + ) + expect(width2).toMatchInlineSnapshot(`"5px"`) + }) +}) diff --git a/test/integration/css/test/css-modules.test.js b/test/integration/css/test/css-modules.test.js new file mode 100644 index 0000000000..f2868d65ad --- /dev/null +++ b/test/integration/css/test/css-modules.test.js @@ -0,0 +1,455 @@ +/* eslint-env jest */ +import cheerio from 'cheerio' +import 'flat-map-polyfill' +import { readdir, readFile, remove } from 'fs-extra' +import { + check, + File, + findPort, + killApp, + launchApp, + nextBuild, + nextStart, + renderViaHTTP, + waitFor, +} from 'next-test-utils' +import webdriver from 'next-webdriver' +import { join } from 'path' + +const fixturesDir = join(__dirname, '../..', 'css-fixtures') + +// https://github.com/vercel/next.js/issues/12343 +describe('Basic CSS Modules Ordering', () => { + const appDir = join(fixturesDir, 'next-issue-12343') + let app, appPort + + function tests() { + async function checkGreenButton(browser) { + await browser.waitForElementByCss('#link-other') + const titleColor = await browser.eval( + `window.getComputedStyle(document.querySelector('#link-other')).backgroundColor` + ) + expect(titleColor).toBe('rgb(0, 255, 0)') + } + async function checkPinkButton(browser) { + await browser.waitForElementByCss('#link-index') + const titleColor = await browser.eval( + `window.getComputedStyle(document.querySelector('#link-index')).backgroundColor` + ) + expect(titleColor).toBe('rgb(255, 105, 180)') + } + + it('should have correct color on index page (on load)', async () => { + const browser = await webdriver(appPort, '/') + try { + await checkGreenButton(browser) + } finally { + await browser.close() + } + }) + + it('should have correct color on index page (on hover)', async () => { + const browser = await webdriver(appPort, '/') + try { + await checkGreenButton(browser) + await browser.waitForElementByCss('#link-other').moveTo() + await waitFor(2000) + await checkGreenButton(browser) + } finally { + await browser.close() + } + }) + + it('should have correct color on index page (on nav)', async () => { + const browser = await webdriver(appPort, '/') + try { + await checkGreenButton(browser) + await browser.waitForElementByCss('#link-other').click() + + // Wait for navigation: + await browser.waitForElementByCss('#link-index') + await checkPinkButton(browser) + + // Navigate back to index: + await browser.waitForElementByCss('#link-index').click() + await checkGreenButton(browser) + } finally { + await browser.close() + } + }) + } + + describe('Development Mode', () => { + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + beforeAll(async () => { + appPort = await findPort() + app = await launchApp(appDir, appPort) + }) + afterAll(async () => { + await killApp(app) + }) + + tests() + }) + + describe('Production Mode', () => { + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + beforeAll(async () => { + await nextBuild(appDir, [], {}) + appPort = await findPort() + app = await nextStart(appDir, appPort) + }) + afterAll(async () => { + await killApp(app) + }) + + tests() + }) +}) + +describe('should handle unresolved files gracefully', () => { + const workDir = join(fixturesDir, 'unresolved-css-url') + + it('should build correctly', async () => { + await remove(join(workDir, '.next')) + const { code } = await nextBuild(workDir) + expect(code).toBe(0) + }) + + it('should have correct file references in CSS output', async () => { + const cssFiles = await readdir(join(workDir, '.next/static/css')) + + for (const file of cssFiles) { + if (file.endsWith('.css.map')) continue + + const content = await readFile( + join(workDir, '.next/static/css', file), + 'utf8' + ) + console.log(file, content) + + // if it is the combined global CSS file there are double the expected + // results + const howMany = content.includes('p{') || content.includes('p,') ? 2 : 1 + + expect(content.match(/\(\/vercel\.svg/g).length).toBe(howMany) + // expect(content.match(/\(vercel\.svg/g).length).toBe(howMany) + expect(content.match(/\(\/_next\/static\/media/g).length).toBe(1) + expect(content.match(/\(https:\/\//g).length).toBe(howMany) + } + }) +}) + +describe('Data URLs', () => { + const workDir = join(fixturesDir, 'data-url') + + it('should compile successfully', async () => { + await remove(join(workDir, '.next')) + const { code } = await nextBuild(workDir) + expect(code).toBe(0) + }) + + it('should have emitted expected files', async () => { + const cssFolder = join(workDir, '.next/static/css') + const files = await readdir(cssFolder) + const cssFiles = files.filter((f) => /\.css$/.test(f)) + + expect(cssFiles.length).toBe(1) + const cssContent = await readFile(join(cssFolder, cssFiles[0]), 'utf8') + expect(cssContent.replace(/\/\*.*?\*\//g, '').trim()).toMatch( + /background:url\("data:[^"]+"\)/ + ) + }) +}) + +describe('Ordering with Global CSS and Modules (dev)', () => { + const appDir = join(fixturesDir, 'global-and-module-ordering') + + let appPort + let app + beforeAll(async () => { + await remove(join(appDir, '.next')) + appPort = await findPort() + app = await launchApp(appDir, appPort) + }) + afterAll(async () => { + await killApp(app) + }) + + it('should not execute scripts in any order', async () => { + const content = await renderViaHTTP(appPort, '/') + const $ = cheerio.load(content) + + let asyncCount = 0 + let totalCount = 0 + for (const script of $('script').toArray()) { + ++totalCount + if ('async' in script.attribs) { + ++asyncCount + } + } + + expect(asyncCount).toBe(0) + expect(totalCount).not.toBe(0) + }) + + it('should have the correct color (css ordering)', async () => { + const browser = await webdriver(appPort, '/') + + const currentColor = await browser.eval( + `window.getComputedStyle(document.querySelector('#blueText')).color` + ) + expect(currentColor).toMatchInlineSnapshot(`"rgb(0, 0, 255)"`) + }) + + it('should have the correct color (css ordering) during hot reloads', async () => { + let browser + try { + browser = await webdriver(appPort, '/') + + const blueColor = await browser.eval( + `window.getComputedStyle(document.querySelector('#blueText')).color` + ) + expect(blueColor).toMatchInlineSnapshot(`"rgb(0, 0, 255)"`) + + const yellowColor = await browser.eval( + `window.getComputedStyle(document.querySelector('#yellowText')).color` + ) + expect(yellowColor).toMatchInlineSnapshot(`"rgb(255, 255, 0)"`) + + const cssFile = new File(join(appDir, 'pages/index.module.css')) + try { + cssFile.replace('color: yellow;', 'color: rgb(1, 1, 1);') + await check( + () => + browser.eval( + `window.getComputedStyle(document.querySelector('#yellowText')).color` + ), + 'rgb(1, 1, 1)' + ) + await check( + () => + browser.eval( + `window.getComputedStyle(document.querySelector('#blueText')).color` + ), + 'rgb(0, 0, 255)' + ) + } finally { + cssFile.restore() + } + } finally { + if (browser) { + await browser.close() + } + } + }) +}) + +describe('Ordering with Global CSS and Modules (prod)', () => { + const appDir = join(fixturesDir, 'global-and-module-ordering') + + let appPort + let app + let stdout + let code + beforeAll(async () => { + await remove(join(appDir, '.next')) + ;({ code, stdout } = await nextBuild(appDir, [], { + stdout: true, + })) + appPort = await findPort() + app = await nextStart(appDir, appPort) + }) + afterAll(async () => { + await killApp(app) + }) + + it('should have compiled successfully', () => { + expect(code).toBe(0) + expect(stdout).toMatch(/Compiled successfully/) + }) + + it('should have the correct color (css ordering)', async () => { + const browser = await webdriver(appPort, '/') + + const currentColor = await browser.eval( + `window.getComputedStyle(document.querySelector('#blueText')).color` + ) + expect(currentColor).toMatchInlineSnapshot(`"rgb(0, 0, 255)"`) + }) +}) + +// https://github.com/vercel/next.js/issues/12445 +describe('CSS Modules Composes Ordering', () => { + const appDir = join(fixturesDir, 'composes-ordering') + let app, appPort + + function tests(isDev = false) { + async function checkBlackTitle(browser) { + await browser.waitForElementByCss('#black-title') + const titleColor = await browser.eval( + `window.getComputedStyle(document.querySelector('#black-title')).color` + ) + expect(titleColor).toBe('rgb(17, 17, 17)') + } + async function checkRedTitle(browser) { + await browser.waitForElementByCss('#red-title') + const titleColor = await browser.eval( + `window.getComputedStyle(document.querySelector('#red-title')).color` + ) + expect(titleColor).toBe('rgb(255, 0, 0)') + } + + it('should have correct color on index page (on load)', async () => { + const browser = await webdriver(appPort, '/') + try { + await checkBlackTitle(browser) + } finally { + await browser.close() + } + }) + + it('should have correct color on index page (on hover)', async () => { + const browser = await webdriver(appPort, '/') + try { + await checkBlackTitle(browser) + await browser.waitForElementByCss('#link-other').moveTo() + await waitFor(2000) + await checkBlackTitle(browser) + } finally { + await browser.close() + } + }) + + if (!isDev) { + it('should not change color on hover', async () => { + const browser = await webdriver(appPort, '/') + try { + await checkBlackTitle(browser) + await browser.waitForElementByCss('#link-other').moveTo() + await waitFor(2000) + await checkBlackTitle(browser) + } finally { + await browser.close() + } + }) + + it('should have correct CSS injection order', async () => { + const browser = await webdriver(appPort, '/') + try { + await checkBlackTitle(browser) + + const prevSiblingHref = await browser.eval( + `document.querySelector('link[rel=stylesheet][data-n-p]').previousSibling.getAttribute('href')` + ) + const currentPageHref = await browser.eval( + `document.querySelector('link[rel=stylesheet][data-n-p]').getAttribute('href')` + ) + expect(prevSiblingHref).toBeDefined() + expect(prevSiblingHref).toBe(currentPageHref) + + // Navigate to other: + await browser.waitForElementByCss('#link-other').click() + await checkRedTitle(browser) + + const newPrevSibling = await browser.eval( + `document.querySelector('style[data-n-href]').previousSibling.getAttribute('data-n-css')` + ) + const newPageHref = await browser.eval( + `document.querySelector('style[data-n-href]').getAttribute('data-n-href')` + ) + expect(newPrevSibling).toBe('') + expect(newPageHref).toBeDefined() + expect(newPageHref).not.toBe(currentPageHref) + + // Navigate to home: + await browser.waitForElementByCss('#link-index').click() + await checkBlackTitle(browser) + + const newPrevSibling2 = await browser.eval( + `document.querySelector('style[data-n-href]').previousSibling.getAttribute('data-n-css')` + ) + const newPageHref2 = await browser.eval( + `document.querySelector('style[data-n-href]').getAttribute('data-n-href')` + ) + expect(newPrevSibling2).toBe('') + expect(newPageHref2).toBeDefined() + expect(newPageHref2).toBe(currentPageHref) + } finally { + await browser.close() + } + }) + } + + it('should have correct color on index page (on nav from index)', async () => { + const browser = await webdriver(appPort, '/') + try { + await checkBlackTitle(browser) + await browser.waitForElementByCss('#link-other').click() + + // Wait for navigation: + await browser.waitForElementByCss('#link-index') + await checkRedTitle(browser) + + // Navigate back to index: + await browser.waitForElementByCss('#link-index').click() + await checkBlackTitle(browser) + } finally { + await browser.close() + } + }) + + it('should have correct color on index page (on nav from other)', async () => { + const browser = await webdriver(appPort, '/other') + try { + await checkRedTitle(browser) + await browser.waitForElementByCss('#link-index').click() + + // Wait for navigation: + await browser.waitForElementByCss('#link-other') + await checkBlackTitle(browser) + + // Navigate back to other: + await browser.waitForElementByCss('#link-other').click() + await checkRedTitle(browser) + } finally { + await browser.close() + } + }) + } + + describe('Development Mode', () => { + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + beforeAll(async () => { + appPort = await findPort() + app = await launchApp(appDir, appPort) + }) + afterAll(async () => { + await killApp(app) + }) + + tests(true) + }) + + describe('Production Mode', () => { + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + beforeAll(async () => { + await nextBuild(appDir, [], {}) + appPort = await findPort() + app = await nextStart(appDir, appPort) + }) + afterAll(async () => { + await killApp(app) + }) + + tests() + }) +}) diff --git a/test/integration/css/test/css-rendering.test.js b/test/integration/css/test/css-rendering.test.js new file mode 100644 index 0000000000..846b74ddf9 --- /dev/null +++ b/test/integration/css/test/css-rendering.test.js @@ -0,0 +1,406 @@ +/* eslint-env jest */ +import 'flat-map-polyfill' +import { pathExists, readFile, readJSON, remove } from 'fs-extra' +import { + check, + findPort, + killApp, + nextBuild, + nextStart, + waitFor, +} from 'next-test-utils' +import webdriver from 'next-webdriver' +import { join } from 'path' + +const fixturesDir = join(__dirname, '../..', 'css-fixtures') + +describe('CSS Support', () => { + describe('CSS Import from node_modules', () => { + const appDir = join(fixturesDir, 'npm-import-bad') + + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + + it('should fail the build', async () => { + const { code, stderr } = await nextBuild(appDir, [], { stderr: true }) + + expect(code).toBe(0) + expect(stderr).not.toMatch(/Can't resolve '[^']*?nprogress[^']*?'/) + expect(stderr).not.toMatch(/Build error occurred/) + }) + }) + + // https://github.com/vercel/next.js/issues/18557 + describe('CSS page transition inject