Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support Next.JS version 14 #29558

Merged
merged 4 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/cache-version.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Bump this version to force CI to re-create the cache from scratch.

05-09-24
05-23-24
10 changes: 5 additions & 5 deletions .circleci/workflows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ mainBuildFilters: &mainBuildFilters
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
- 'update-v8-snapshot-cache-on-develop'
- 'publish-binary'
- 'feat/vite_5_support'
- 'feat/support_next_14'

# usually we don't build Mac app - it takes a long time
# but sometimes we want to really confirm we are doing the right thing
Expand All @@ -42,7 +42,7 @@ macWorkflowFilters: &darwin-workflow-filters
- equal: [ develop, << pipeline.git.branch >> ]
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
- equal: [ 'feat/vite_5_support', << pipeline.git.branch >> ]
- equal: [ 'feat/support_next_14', << pipeline.git.branch >> ]
- matches:
pattern: /^release\/\d+\.\d+\.\d+$/
value: << pipeline.git.branch >>
Expand All @@ -53,7 +53,7 @@ linuxArm64WorkflowFilters: &linux-arm64-workflow-filters
- equal: [ develop, << pipeline.git.branch >> ]
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
- equal: [ 'feat/vite_5_support', << pipeline.git.branch >> ]
- equal: [ 'feat/support_next_14', << pipeline.git.branch >> ]
- matches:
pattern: /^release\/\d+\.\d+\.\d+$/
value: << pipeline.git.branch >>
Expand All @@ -76,7 +76,7 @@ windowsWorkflowFilters: &windows-workflow-filters
- equal: [ develop, << pipeline.git.branch >> ]
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
- equal: [ 'chore/fix_illegal_characters_in_windows', << pipeline.git.branch >> ]
- equal: [ 'feat/support_next_14', << pipeline.git.branch >> ]
- matches:
pattern: /^release\/\d+\.\d+\.\d+$/
value: << pipeline.git.branch >>
Expand Down Expand Up @@ -152,7 +152,7 @@ commands:
name: Set environment variable to determine whether or not to persist artifacts
command: |
echo "Setting SHOULD_PERSIST_ARTIFACTS variable"
echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "feat/vite_5_support" ]]; then
echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "feat/support_next_14" ]]; then
export SHOULD_PERSIST_ARTIFACTS=true
fi' >> "$BASH_ENV"
# You must run `setup_should_persist_artifacts` command and be using bash before running this command
Expand Down
8 changes: 6 additions & 2 deletions cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
<!-- See the ../guides/writing-the-cypress-changelog.md for details on writing the changelog. -->
## 13.10.1
## 13.11.0

_Released 5/28/2024 (PENDING)_
_Released 6/4/2024 (PENDING)_

**Features:**

- Added support for [Next.js 14](https://nextjs.org/blog/next-14) for component testing. Addresses [#28185](https://github.com/cypress-io/cypress/issues/28185).

**Bugfixes:**

Expand Down
100 changes: 98 additions & 2 deletions npm/webpack-dev-server/cypress/e2e/next.cy.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
/// <reference path="../support/e2e.ts" />
import type { ProjectFixtureDir } from '@tooling/system-tests/lib/fixtureDirs'

const WEBPACK_REACT: ProjectFixtureDir[] = ['next-12', 'next-12.1.6', 'next-13', 'next-13-tsconfig']

const WEBPACK_REACT: ProjectFixtureDir[] = ['next-12', 'next-12.1.6', 'next-13', 'next-13-tsconfig', 'next-14']
// Add to this list to focus on a particular permutation
const ONLY_PROJECTS: ProjectFixtureDir[] = []

Expand Down Expand Up @@ -106,3 +105,100 @@ for (const project of WEBPACK_REACT) {
})
})
}

// Since next-14-tsconfig-tailwind does not use the fixture directory we need to write our own test suite
// We want to specifically test typescript files with next-14 as there have been known problems with
// module: bundler and cypress compatibility
describe(`Working with next-14-tsconfig-tailwind`, () => {
beforeEach(() => {
cy.scaffoldProject('next-14-tsconfig-tailwind')
cy.openProject('next-14-tsconfig-tailwind', ['--component'])
cy.startAppServer('component')
})

it('should mount a passing test', () => {
cy.visitApp()
cy.specsPageIsVisible()
cy.contains('page.cy.tsx').click()
cy.waitForSpecToFinish({ passCount: 1 })
})

it('should live-reload on src changes', () => {
cy.visitApp()
cy.specsPageIsVisible()

cy.contains('page.cy.tsx').click()
cy.waitForSpecToFinish({ passCount: 1 })

cy.withCtx(async (ctx) => {
const indexPath = ctx.path.join('app', 'page.tsx')

await ctx.actions.file.writeFileInProject(
indexPath,
(await ctx.file.readFileInProject(indexPath)).replace('Welcome to', 'Hello from'),
)
})

cy.waitForSpecToFinish({ failCount: 1 })
cy.get('.test-err-code-frame').should('be.visible')

cy.withCtx(async (ctx) => {
const indexTestPath = ctx.path.join('app', 'page.cy.tsx')

await ctx.actions.file.writeFileInProject(
indexTestPath,
(await ctx.file.readFileInProject(indexTestPath)).replace('Welcome to', 'Hello from'),
)
})

cy.waitForSpecToFinish({ passCount: 1 })
})

it('should show compilation errors on src changes', () => {
cy.visitApp()
cy.specsPageIsVisible()

cy.contains('page.cy.tsx').click()
cy.waitForSpecToFinish({ passCount: 1 })

// Create compilation error
cy.withCtx(async (ctx) => {
const indexPath = ctx.path.join('app', 'page.tsx')

await ctx.actions.file.writeFileInProject(
indexPath,
(await ctx.file.readFileInProject(indexPath)).replace('export', 'expart'),
)
})

// The test should fail and the stack trace should appear in the command log
cy.waitForSpecToFinish({ failCount: 1 })
cy.contains('The following error originated from your test code, not from Cypress.').should('exist')
})

it('should detect new spec', { retries: 15 }, () => {
cy.visitApp()
cy.specsPageIsVisible()

cy.withCtx(async (ctx) => {
const newTestPath = ctx.path.join('app', 'New.cy.tsx')
const indexTestPath = ctx.path.join('app', 'page.cy.tsx')

await ctx.actions.file.writeFileInProject(
newTestPath,
await ctx.file.readFileInProject(indexTestPath),
)
})

cy.contains('New.cy.tsx').click()
cy.waitForSpecToFinish({ passCount: 1 })
})

// Make sure tailwind styles are appearing in the test.
it('should allow import of global styles in support file', { retries: 15 }, () => {
cy.visitApp()
cy.specsPageIsVisible()
cy.contains('page-styles.cy.tsx').click()
cy.waitForSpecToFinish({ passCount: 1 })
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ export function sourceWebpackDevServer (config: WebpackDevServerConfig, webpackM

throw new CypressWebpackDevServerError(
`Incompatible major versions of webpack and webpack-dev-server!
webpack-dev-server major version ${webpackDevServer.majorVersion} only works with major versions of webpack ${webpackMajorVersion} - saw webpack-dev-server version ${json.version}.
webpack-dev-server major version ${webpackDevServer.majorVersion} only works with major versions of webpack 5 - saw webpack-dev-server version ${json.version}.
If using webpack major version 4, please install webpack-dev-server version 4 to be used with @cypress/webpack-dev-server or upgrade to webpack 5.`,
)
}
Expand Down
10 changes: 5 additions & 5 deletions npm/webpack-dev-server/test/handlers/nextHandler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import { WebpackDevServerConfig } from '../../src/devServer'
import '../support'

const expectWatchOverrides = (webpackConfig: Configuration) => {
expect(webpackConfig.watchOptions?.ignored).to.contain('**/node_modules/!(@cypress/webpack-dev-server/dist/browser.js)**')
expect((webpackConfig.watchOptions?.ignored as RegExp)?.test('**/node_modules/!(@cypress/webpack-dev-server/dist/browser.js)**')).to.be.true
}

const expectPagesDir = (webpackConfig: Configuration, projectRoot: string) => {
const ReactLoadablePlugin: any = webpackConfig.plugins?.find((plugin) => plugin.constructor.name === 'ReactLoadablePlugin')

expect(ReactLoadablePlugin.pagesDir).eq(path.join(projectRoot, 'pages'))
expect(ReactLoadablePlugin.pagesOrAppDir).eq(path.join(projectRoot, 'pages'))
}

const expectWebpackSpan = (webpackConfig: Configuration) => {
Expand Down Expand Up @@ -54,8 +54,8 @@ describe('nextHandler', function () {
// can take a while since we install node_modules
this.timeout(1000 * 60)

it('sources from a next-12 project', async () => {
const projectRoot = await scaffoldMigrationProject('next-12')
it('sources from a next-14 project', async () => {
const projectRoot = await scaffoldMigrationProject('next-14')

process.chdir(projectRoot)

Expand All @@ -75,7 +75,7 @@ describe('nextHandler', function () {
})

it('throws if nodeVersion is set to bundled', async () => {
const projectRoot = await scaffoldMigrationProject('next-12')
const projectRoot = await scaffoldMigrationProject('next-14')

process.chdir(projectRoot)

Expand Down
4 changes: 2 additions & 2 deletions packages/app/cypress/e2e/runner/ct-framework-errors.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,12 @@ describe('Next.js', {
numTestsKeptInMemory: 1,
}, () => {
beforeEach(() => {
cy.scaffoldProject('next-12')
cy.scaffoldProject('next-14')
})

it('error conditions', () => {
const verify = loadErrorSpec({
projectName: 'next-12',
projectName: 'next-14',
configFile: 'cypress.config.js',
filePath: 'cypress/Errors.cy.jsx',
failCount: 4,
Expand Down
4 changes: 2 additions & 2 deletions packages/launchpad/cypress/e2e/config-warning.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,8 @@ describe('component testing dependency warnings', () => {
})

it('does not show warning for project that does not require bundler to be installed', () => {
cy.scaffoldProject('next-12')
cy.openProject('next-12', ['--component'])
cy.scaffoldProject('next-14')
cy.openProject('next-14', ['--component'])
cy.visitLaunchpad()
cy.skipWelcome()
cy.get('[data-cy="warning-alert"]').should('not.exist')
Expand Down
2 changes: 1 addition & 1 deletion packages/scaffold-config/src/dependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export const WIZARD_DEPENDENCY_NEXT = {
package: 'next',
installer: 'next',
description: 'The React Framework for Production',
minVersion: '^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0',
minVersion: '^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0',
} as const

export const WIZARD_DEPENDENCY_ANGULAR_CLI = {
Expand Down
2 changes: 1 addition & 1 deletion packages/scaffold-config/test/unit/detect.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ describe('detectFramework', () => {
expect(actual.bundler).to.eq('vite')
})

;['10.0.0', '11.0.0', '12.0.0'].forEach((v) => {
;['10.0.0', '11.0.0', '12.0.0', '13.0.0', '14.0.0'].forEach((v) => {
it(`Next.js v${v}`, async () => {
const projectPath = await scaffoldMigrationProject('nextjs-unconfigured')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2408,7 +2408,7 @@ Your configFile threw an error from: cypress-webpack.config.ts
We stopped running your tests because your config file crashed.

CypressWebpackDevServerError: Incompatible major versions of webpack and webpack-dev-server!
webpack-dev-server major version 5 only works with major versions of webpack 4 - saw webpack-dev-server version 5.0.4.
webpack-dev-server major version 5 only works with major versions of webpack 5 - saw webpack-dev-server version 5.0.4.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noticed this error was wrong so fixed it here

If using webpack major version 4, please install webpack-dev-server version 4 to be used with @cypress/webpack-dev-server or upgrade to webpack 5.
[stack trace lines]
`
33 changes: 33 additions & 0 deletions system-tests/projects/next-14-tsconfig-tailwind/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

:root {
--foreground-rgb: 0, 0, 0;
--background-start-rgb: 214, 219, 220;
--background-end-rgb: 255, 255, 255;
}

@media (prefers-color-scheme: dark) {
:root {
--foreground-rgb: 255, 255, 255;
--background-start-rgb: 0, 0, 0;
--background-end-rgb: 0, 0, 0;
}
}

body {
color: rgb(var(--foreground-rgb));
background: linear-gradient(
to bottom,
transparent,
rgb(var(--background-end-rgb))
)
rgb(var(--background-start-rgb));
}

@layer utilities {
.text-balance {
text-wrap: balance;
}
}
22 changes: 22 additions & 0 deletions system-tests/projects/next-14-tsconfig-tailwind/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import './globals.css'

const inter = Inter({ subsets: ['latin'] })

export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
}

export default function RootLayout ({
children,
}: Readonly<{
children: React.ReactNode
}>) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react'
import Home from './page'

describe('<Home />', () => {
it('renders', () => {
cy.mount(<Home />)
cy.contains('h1', 'Welcome to Next.js!')

// verify tailwind classes are applied correctly via import from support file.
cy.get('main').should('have.css', 'background-color', 'rgb(245, 158, 11)')
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react'
import Home from './page'

describe('<Home />', () => {
it('renders', () => {
cy.mount(<Home />)
cy.contains('h1', 'Welcome to Next.js!')
})
})
7 changes: 7 additions & 0 deletions system-tests/projects/next-14-tsconfig-tailwind/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function Home () {
return (
<main className="bg-amber-500">
<h1> Welcome to Next.js! </h1>
</main>
)
}
24 changes: 24 additions & 0 deletions system-tests/projects/next-14-tsconfig-tailwind/cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import path from 'path'
import { defineConfig } from 'cypress'

export default defineConfig({
component: {
devServer: {
framework: 'next',
bundler: 'webpack',
// Necessary due to cypress/react resolving from cypress/node_modules rather than the project root
webpackConfig: {
resolve: {
alias: {
'react': path.resolve(__dirname, './node_modules/react'),
'react-dom': path.resolve(__dirname, './node_modules/react-dom'),
},
},
},
},
fixturesFolder: false,
},
// These tests should run quickly / fail quickly,
// since we intentionally causing error states for testing
defaultCommandTimeout: 1000,
})
Loading
Loading