diff --git a/examples/with-playwright/.gitignore b/examples/with-playwright/.gitignore new file mode 100644 index 0000000000..ef52b3838d --- /dev/null +++ b/examples/with-playwright/.gitignore @@ -0,0 +1,35 @@ +# 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 +test-results/ diff --git a/examples/with-playwright/README.md b/examples/with-playwright/README.md new file mode 100644 index 0000000000..89965c2c29 --- /dev/null +++ b/examples/with-playwright/README.md @@ -0,0 +1,27 @@ +# Next.js + Playwright + +This example shows how to configure Playwright to work with Next.js. + +## Preview + +Preview the example live on [StackBlitz](http://stackblitz.com/): + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/vercel/next.js/tree/canary/examples/with-playwright) + +## Deploy your own + +Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example): + +[![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-playwright&project-name=with-playwright&repository-name=with-playwright) + +## 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-playwright with-playwright-app +# or +yarn create next-app --example with-playwright with-playwright-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-playwright/e2e/example.spec.ts b/examples/with-playwright/e2e/example.spec.ts new file mode 100644 index 0000000000..547a6c4002 --- /dev/null +++ b/examples/with-playwright/e2e/example.spec.ts @@ -0,0 +1,12 @@ +import { test, expect } from '@playwright/test' + +test('should navigate to the about page', async ({ page }) => { + // Start from the index page (the baseURL is set via the webServer in the playwright.config.ts) + await page.goto('/') + // Find an element with the text 'About Page' and click on it + await page.click('text=About Page') + // The new url should be "/about" (baseURL is used there) + await expect(page).toHaveURL('/about') + // The new page should contain an h1 with "About Page" + await expect(page.locator('h1')).toContainText('About Page') +}) diff --git a/examples/with-playwright/package.json b/examples/with-playwright/package.json new file mode 100644 index 0000000000..9c98887da6 --- /dev/null +++ b/examples/with-playwright/package.json @@ -0,0 +1,17 @@ +{ + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "test:e2e": "playwright test" + }, + "dependencies": { + "next": "latest", + "react": "17.0.2", + "react-dom": "17.0.2" + }, + "devDependencies": { + "@playwright/test": "^1.15.0" + } +} diff --git a/examples/with-playwright/pages/_app.js b/examples/with-playwright/pages/_app.js new file mode 100644 index 0000000000..1e1cec9242 --- /dev/null +++ b/examples/with-playwright/pages/_app.js @@ -0,0 +1,7 @@ +import '../styles/globals.css' + +function MyApp({ Component, pageProps }) { + return +} + +export default MyApp diff --git a/examples/with-playwright/pages/about.js b/examples/with-playwright/pages/about.js new file mode 100644 index 0000000000..0db6440474 --- /dev/null +++ b/examples/with-playwright/pages/about.js @@ -0,0 +1,17 @@ +import styles from '../styles/Home.module.css' +import Link from 'next/link' + +export default function About() { + return ( +
+
+

About Page

+

+ + ← Go Back + +

+
+
+ ) +} diff --git a/examples/with-playwright/pages/index.js b/examples/with-playwright/pages/index.js new file mode 100644 index 0000000000..25a4a79171 --- /dev/null +++ b/examples/with-playwright/pages/index.js @@ -0,0 +1,77 @@ +import Head from 'next/head' +import Image from 'next/image' +import Link from 'next/link' +import styles from '../styles/Home.module.css' + +export default function Home() { + return ( +
+ + Create Next App + + + + +
+

+ Welcome to Next.js! +

+ +

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

+ +
+ + +

About Page →

+

Playwright will test if this link is working.

+
+ + + +

Documentation →

+

Find in-depth information about Next.js features and API.

+
+ + +

Learn →

+

Learn about Next.js in an interactive course with quizzes!

+
+ + +

Examples →

+

Discover and deploy boilerplate example Next.js projects.

+
+ + +

Deploy →

+

+ Instantly deploy your Next.js site to a public URL with Vercel. +

+
+
+
+ + +
+ ) +} diff --git a/examples/with-playwright/playwright.config.ts b/examples/with-playwright/playwright.config.ts new file mode 100644 index 0000000000..3254888985 --- /dev/null +++ b/examples/with-playwright/playwright.config.ts @@ -0,0 +1,67 @@ +import { PlaywrightTestConfig, devices } from '@playwright/test' +import path from 'path' + +// Reference: https://playwright.dev/docs/test-configuration +const config: PlaywrightTestConfig = { + // Timeout per test + timeout: 30 * 1000, + // Test directory + testDir: path.join(__dirname, 'e2e'), + // If a test fails, retry it additional 2 times + retries: 2, + // Artifacts folder where screenshots, videos, and traces are stored. + outputDir: 'test-results/', + + // Run your local dev server before starting the tests: + // https://playwright.dev/docs/test-advanced#launching-a-development-web-server-during-the-tests + webServer: { + command: 'npm run dev', + port: 3000, + timeout: 120 * 1000, + reuseExistingServer: !process.env.CI, + }, + + use: { + // Retry a test if its failing with enabled tracing. This allows you to analyse the DOM, console logs, network traffic etc. + // More information: https://playwright.dev/docs/trace-viewer + trace: 'retry-with-trace', + + // All available context options: https://playwright.dev/docs/api/class-browser#browser-new-context + // contextOptions: { + // ignoreHTTPSErrors: true, + // }, + }, + + projects: [ + { + name: 'Desktop Chrome', + use: { + ...devices['Desktop Chrome'], + }, + }, + // { + // name: 'Desktop Firefox', + // use: { + // ...devices['Desktop Firefox'], + // }, + // }, + // { + // name: 'Desktop Safari', + // use: { + // ...devices['Desktop Safari'], + // }, + // }, + // Test against mobile viewports. + { + name: 'Mobile Chrome', + use: { + ...devices['Pixel 5'], + }, + }, + { + name: 'Mobile Safari', + use: devices['iPhone 12'], + }, + ], +} +export default config diff --git a/examples/with-playwright/public/favicon.ico b/examples/with-playwright/public/favicon.ico new file mode 100644 index 0000000000..718d6fea48 Binary files /dev/null and b/examples/with-playwright/public/favicon.ico differ diff --git a/examples/with-playwright/public/vercel.svg b/examples/with-playwright/public/vercel.svg new file mode 100644 index 0000000000..fbf0e25a65 --- /dev/null +++ b/examples/with-playwright/public/vercel.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/examples/with-playwright/styles/Home.module.css b/examples/with-playwright/styles/Home.module.css new file mode 100644 index 0000000000..35454bb748 --- /dev/null +++ b/examples/with-playwright/styles/Home.module.css @@ -0,0 +1,121 @@ +.container { + min-height: 100vh; + padding: 0 0.5rem; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + height: 100vh; +} + +.main { + padding: 5rem 0; + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.footer { + width: 100%; + height: 100px; + border-top: 1px solid #eaeaea; + display: flex; + 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 { + 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; + margin-top: 3rem; +} + +.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; + width: 45%; +} + +.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-playwright/styles/globals.css b/examples/with-playwright/styles/globals.css new file mode 100644 index 0000000000..e5e2dcc23b --- /dev/null +++ b/examples/with-playwright/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; +}