diff --git a/docs/testing.md b/docs/testing.md index 500016c6bff84fa..d24cd71f3249a9e 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -10,6 +10,7 @@ description: Learn how to set up Next.js with three commonly used testing tools
  • Next.js with Cypress
  • Next.js with Playwright
  • Next.js with Jest and React Testing Library
  • +
  • Next.js with Vitest
  • diff --git a/examples/with-vitest/.gitignore b/examples/with-vitest/.gitignore new file mode 100644 index 000000000000000..1437c53f70bc211 --- /dev/null +++ b/examples/with-vitest/.gitignore @@ -0,0 +1,34 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel diff --git a/examples/with-vitest/README.md b/examples/with-vitest/README.md new file mode 100644 index 000000000000000..5bd869b5c98a63f --- /dev/null +++ b/examples/with-vitest/README.md @@ -0,0 +1,23 @@ +# Vitest + +This example shows how to use [Vitest](https://github.com/vitest-dev/vitest) with Next.js. + +## Deploy your own + +Deploy the example using [Vercel](https://vercel.com/) or preview live with [StackBlitz](https://stackblitz.com/github/vercel/next.js/tree/canary/examples/with-vitest) + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-vitest&project-name=with-vitest&repository-name=with-vitest) + +## How to use + +Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example: + +```bash +npx create-next-app --example with-vitest with-vitest-app +# or +yarn create next-app --example with-vitest with-vitest-app +# or +pnpm create next-app -- --example with-vitest with-vitest-app +``` + +Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). diff --git a/examples/with-vitest/__tests__/Home.test.tsx b/examples/with-vitest/__tests__/Home.test.tsx new file mode 100644 index 000000000000000..c6f8dc2303427a2 --- /dev/null +++ b/examples/with-vitest/__tests__/Home.test.tsx @@ -0,0 +1,15 @@ +import { expect, test } from 'vitest' +import { render, screen, within } from '@testing-library/react' +import Home from '../pages' + +test('home', () => { + render() + const main = within(screen.getByRole('main')) + expect( + main.getByRole('heading', { level: 1, name: /welcome to next\.js!/i }) + ).toBeDefined() + + const footer = within(screen.getByRole('contentinfo')) + const link = within(footer.getByRole('link')) + expect(link.getByRole('img', { name: /vercel logo/i })).toBeDefined() +}) diff --git a/examples/with-vitest/next-env.d.ts b/examples/with-vitest/next-env.d.ts new file mode 100644 index 000000000000000..4f11a03dc6cc37f --- /dev/null +++ b/examples/with-vitest/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/examples/with-vitest/next.config.js b/examples/with-vitest/next.config.js new file mode 100644 index 000000000000000..a843cbee09afaad --- /dev/null +++ b/examples/with-vitest/next.config.js @@ -0,0 +1,6 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, +} + +module.exports = nextConfig diff --git a/examples/with-vitest/package.json b/examples/with-vitest/package.json new file mode 100644 index 000000000000000..973a91ffeed555a --- /dev/null +++ b/examples/with-vitest/package.json @@ -0,0 +1,23 @@ +{ + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "test": "vitest" + }, + "dependencies": { + "next": "latest", + "react": "18.0.0", + "react-dom": "18.0.0" + }, + "devDependencies": { + "@testing-library/react": "^12.1.4", + "@types/node": "17.0.23", + "@types/react": "17.0.43", + "@vitejs/plugin-react": "1.3.0", + "jsdom": "^19.0.0", + "typescript": "4.6.3", + "vitest": "0.8.4" + } +} diff --git a/examples/with-vitest/pages/_app.tsx b/examples/with-vitest/pages/_app.tsx new file mode 100644 index 000000000000000..33da2fce548ca16 --- /dev/null +++ b/examples/with-vitest/pages/_app.tsx @@ -0,0 +1,6 @@ +import '../styles/globals.css' +import type { AppProps } from 'next/app' + +export default function MyApp({ Component, pageProps }: AppProps) { + return +} diff --git a/examples/with-vitest/pages/index.tsx b/examples/with-vitest/pages/index.tsx new file mode 100644 index 000000000000000..86b5b3b5bf3fdf0 --- /dev/null +++ b/examples/with-vitest/pages/index.tsx @@ -0,0 +1,72 @@ +import type { NextPage } from 'next' +import Head from 'next/head' +import Image from 'next/image' +import styles from '../styles/Home.module.css' + +const Home: NextPage = () => { + return ( +
    + + Create Next App + + + + +
    +

    + Welcome to Next.js! +

    + +

    + Get started by editing{' '} + pages/index.tsx +

    + + +
    + + +
    + ) +} + +export default Home diff --git a/examples/with-vitest/public/favicon.ico b/examples/with-vitest/public/favicon.ico new file mode 100644 index 000000000000000..d14dbd1d8638ded Binary files /dev/null and b/examples/with-vitest/public/favicon.ico differ diff --git a/examples/with-vitest/public/vercel.svg b/examples/with-vitest/public/vercel.svg new file mode 100644 index 000000000000000..fbf0e25a651c289 --- /dev/null +++ b/examples/with-vitest/public/vercel.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/examples/with-vitest/styles/Home.module.css b/examples/with-vitest/styles/Home.module.css new file mode 100644 index 000000000000000..32a57d52f34c482 --- /dev/null +++ b/examples/with-vitest/styles/Home.module.css @@ -0,0 +1,116 @@ +.container { + padding: 0 2rem; +} + +.main { + min-height: 100vh; + padding: 4rem 0; + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.footer { + display: flex; + flex: 1; + padding: 2rem 0; + border-top: 1px solid #eaeaea; + justify-content: center; + align-items: center; +} + +.footer a { + display: flex; + justify-content: center; + align-items: center; + flex-grow: 1; +} + +.title a { + color: #0070f3; + text-decoration: none; +} + +.title a:hover, +.title a:focus, +.title a:active { + text-decoration: underline; +} + +.title { + margin: 0; + line-height: 1.15; + font-size: 4rem; +} + +.title, +.description { + text-align: center; +} + +.description { + margin: 4rem 0; + line-height: 1.5; + font-size: 1.5rem; +} + +.code { + background: #fafafa; + border-radius: 5px; + padding: 0.75rem; + font-size: 1.1rem; + font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, + Bitstream Vera Sans Mono, Courier New, monospace; +} + +.grid { + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + max-width: 800px; +} + +.card { + margin: 1rem; + padding: 1.5rem; + text-align: left; + color: inherit; + text-decoration: none; + border: 1px solid #eaeaea; + border-radius: 10px; + transition: color 0.15s ease, border-color 0.15s ease; + max-width: 300px; +} + +.card:hover, +.card:focus, +.card:active { + color: #0070f3; + border-color: #0070f3; +} + +.card h2 { + margin: 0 0 1rem 0; + font-size: 1.5rem; +} + +.card p { + margin: 0; + font-size: 1.25rem; + line-height: 1.5; +} + +.logo { + height: 1em; + margin-left: 0.5rem; +} + +@media (max-width: 600px) { + .grid { + width: 100%; + flex-direction: column; + } +} diff --git a/examples/with-vitest/styles/globals.css b/examples/with-vitest/styles/globals.css new file mode 100644 index 000000000000000..e5e2dcc23baf192 --- /dev/null +++ b/examples/with-vitest/styles/globals.css @@ -0,0 +1,16 @@ +html, +body { + padding: 0; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, + Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; +} + +a { + color: inherit; + text-decoration: none; +} + +* { + box-sizing: border-box; +} diff --git a/examples/with-vitest/tsconfig.json b/examples/with-vitest/tsconfig.json new file mode 100644 index 000000000000000..99710e857874ff8 --- /dev/null +++ b/examples/with-vitest/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/examples/with-vitest/vitest.config.ts b/examples/with-vitest/vitest.config.ts new file mode 100644 index 000000000000000..e82ca6b60b1d660 --- /dev/null +++ b/examples/with-vitest/vitest.config.ts @@ -0,0 +1,12 @@ +/// + +import { defineConfig } from 'vitest/config' +import react from '@vitejs/plugin-react' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + test: { + environment: 'jsdom', + }, +})