Skip to content

Commit

Permalink
chore: Split e2e and playground
Browse files Browse the repository at this point in the history
  • Loading branch information
franky47 committed Nov 8, 2023
1 parent cef5808 commit 366e394
Show file tree
Hide file tree
Showing 42 changed files with 895 additions and 89 deletions.
6 changes: 1 addition & 5 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,10 @@ jobs:
- name: Install dependencies
run: pnpm install
- name: Run integration tests
run: pnpm run ci
run: pnpm run test
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
# - uses: coverallsapp/github-action@3dfc5567390f6fa9267c0ee9c251e4c8c3f18949
# name: Report code coverage
# continue-on-error: true
- uses: 47ng/actions-slack-notify@main
name: Notify on Slack
if: always()
Expand Down Expand Up @@ -65,4 +62,3 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
SCEAU_PRIVATE_KEY: ${{ secrets.SCEAU_PRIVATE_KEY }}
4 changes: 2 additions & 2 deletions .github/workflows/test-against-nextjs-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ jobs:
- name: Install dependencies
run: pnpm install
- name: Install Next.js version ${{ inputs.version }}
run: pnpm add --filter next-usequerystate-playground next@${{ inputs.version }}
run: pnpm add --filter e2e next@${{ inputs.version }}
- name: Run integration tests
run: pnpm run ci
run: pnpm run test
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
Expand Down
10 changes: 5 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ First off, thanks for your help!
This monorepo contains:

- The source code for the `next-usequerystate` NPM package, in [`packages/next-usequerystate`](./packages/next-usequerystate).
- A Next.js app under [`packages/playground`](./packages/playground) that serves as:
- A playground deployed at <https://next-usequerystate.vercel.app>
- A host for [end-to-end tests](./packages/playground/cypress//e2e) driven by Cypress
- A Next.js app under [`packages/playground`](./packages/playground) that serves as a playground deployed at <https://next-usequerystate.vercel.app>
- A test bench for [end-to-end tests](./packages/e2e) driven by Cypress

When running `next dev`, this will:

- Build the library and watch for changes using [`tsup`](https://tsup.egoist.dev/)
- Start the playground, which will be available at <http://localhost:3000>.
- Start the end-to-end test bench, which will be available at <http://localhost:3001>.

## Testing

You can run the complete integration test suite with `pnpm run ci`.
You can run the complete integration test suite with `pnpm test`.

It will build the library, run unit tests and typing tests against it, and then
run the end-to-end tests against the playground (which uses the built library).
run the end-to-end tests against the test bench Next.js app (which uses the built library).

When proposing changes or showcasing a bug, adding a minimal reproduction in the
playground can be very helpful.
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
"scripts": {
"dev": "FORCE_COLOR=3 turbo run dev",
"build": "FORCE_COLOR=3 turbo run build",
"test": "FORCE_COLOR=3 turbo run test",
"ci": "FORCE_COLOR=3 turbo run build test",
"test": "FORCE_COLOR=3 turbo run test --filter=next-usequerystate,playground",
"prepare": "husky install"
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { defineConfig } from 'cypress'

export default defineConfig({
e2e: {
baseUrl: `http://localhost:3000`,
baseUrl: `http://localhost:3001`,
video: false,
fixturesFolder: false,
supportFile: false,
Expand Down
File renamed without changes.
File renamed without changes.
6 changes: 6 additions & 0 deletions packages/e2e/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference types="next/navigation-types/compat/navigation" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
37 changes: 37 additions & 0 deletions packages/e2e/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "e2e",
"version": "0.0.0-internal",
"description": "End-to-end test bench for next-usequerystate",
"license": "MIT",
"private": true,
"author": {
"name": "François Best",
"email": "[email protected]",
"url": "https://francoisbest.com"
},
"type": "module",
"scripts": {
"dev": "next dev --port 3001",
"build": "next build",
"start": "next start --port 3001",
"pretest": "cypress install",
"test": "run-p --race start cypress:run",
"cypress:open": "cypress open",
"cypress:run": "cypress run --headless"
},
"dependencies": {
"next": "^14",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"next-usequerystate": "workspace:*"
},
"devDependencies": {
"@types/node": "^20.8.9",
"@types/react": "^18.2.33",
"@types/react-dom": "^18.2.14",
"@types/webpack": "^5.28.4",
"cypress": "^13.3.3",
"npm-run-all": "^4.1.5",
"typescript": "^5.2.2"
}
}
File renamed without changes.
36 changes: 36 additions & 0 deletions packages/e2e/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React, { Suspense } from 'react'
import { HydrationMarker } from '../components/hydration-marker'

export const metadata = {
title: 'next-usequerystate playground',
description:
'useQueryState hook for Next.js - Like React.useState, but stored in the URL query string'
}

export default function RootLayout({
children
}: {
children: React.ReactNode
}) {
return (
<html>
<body>
<Suspense>
<HydrationMarker />
</Suspense>
<header>
<strong>
<code>next-usequerystate</code>
</strong>{' '}
<a href="https://github.com/47ng/next-usequerystate">GitHub</a>{' '}
<a href="https://www.npmjs.com/package/next-usequerystate">NPM</a>{' '}
<a href="https://francoisbest.com/posts/2023/storing-react-state-in-the-url-with-nextjs">
How it works
</a>
</header>
<hr />
{children}
</body>
</html>
)
}
109 changes: 109 additions & 0 deletions packages/e2e/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import Link from 'next/link'

const demos = [
// App router demos
'app/basic-counter',
'app/batching',
'app/builder-pattern',
'app/compound-parsers',
'app/crosslink',
'app/custom-parser',
'app/hex-colors',
'app/parsers',
'app/pretty-urls',
'app/server-side-parsing',
'app/subscribeToQueryUpdates',
'app/repro-359',
'app/repro-376',
// Pages router demos
'pages/server-side-counter'
]

export default function IndexPage() {
return (
<main>
<h1>Playground</h1>
<h2>Demos</h2>
<h3>App router</h3>
<ul>
{demos
.filter(p => p.startsWith('app/'))
.map(path => (
<li key={path}>
<Link href={`/demos/${path.slice(4)}`}>{path.slice(4)}</Link>
</li>
))}
</ul>
<h3>Pages router</h3>
<ul>
{demos
.filter(p => p.startsWith('pages/'))
.map(path => (
<li key={path}>
<Link href={`/demos/pages/${path.slice(6)}`}>
{path.slice(6)}
</Link>
</li>
))}
</ul>
<hr />
<h2>End-to-end integration tests</h2>
<p>⚠️ Don't change these routes without updating integration tests.</p>
<h3>App router</h3>
<ul>
<li>
<Link href="/e2e/app/useQueryState">[static] useQueryState</Link>
</li>
<li>
<Link href="/e2e/app/useQueryState/dynamic/foo">
[dynamic] useQueryState
</Link>
</li>
<li>
<Link href="/e2e/app/useQueryStates">[static] useQueryStates</Link>
</li>
<li>
<Link href="/e2e/app/useQueryStates/dynamic/foo">
[dynamic] useQueryStates
</Link>
</li>
<li>
<Link href="/e2e/app/routing-tour/start/server">
Routing tour starting with server index
</Link>
</li>
<li>
<Link href="/e2e/app/routing-tour/start/client">
Routing tour starting with client index
</Link>
</li>
</ul>
<h3>Pages router</h3>
<ul>
<li>
<Link href="/e2e/pages/useQueryState">[static] useQueryState</Link>
</li>
<li>
<Link href="/e2e/pages/useQueryState/dynamic/foo">
[dynamic] useQueryState
</Link>
</li>
<li>
<Link href="/e2e/pages/useQueryStates">[static] useQueryStates</Link>
</li>
<li>
<Link href="/e2e/pages/useQueryStates/dynamic/foo">
[dynamic] useQueryStates
</Link>
</li>
</ul>
<hr />
<footer>
Made by <a href="https://francoisbest.com">François Best</a> • Follow my
work on <a href="https://github.com/franky47">GitHub</a> and{' '}
<a href="https://mamot.fr/@Franky47">Mastodon</a>{' '}
<a href="mailto:[email protected]">Hire me!</a>
</footer>
</main>
)
}
12 changes: 12 additions & 0 deletions packages/e2e/src/components/demo-page-layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Link from 'next/link'
import { QuerySpy } from './query-spy'

export function DemoPageLayout({ children }: { children: React.ReactNode }) {
return (
<main>
<Link href="/">⬅️ Home</Link>
<QuerySpy />
{children}
</main>
)
}
46 changes: 46 additions & 0 deletions packages/e2e/src/components/query-spy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use client'

import { subscribeToQueryUpdates } from 'next-usequerystate'
import { useSearchParams } from 'next/navigation'
import React from 'react'

export const QuerySpy: React.FC = () => {
const initialSearchParams = useSearchParams()
const [search, setSearch] = React.useState<URLSearchParams>(() => {
if (typeof location !== 'object') {
// SSR
const out = new URLSearchParams()
if (!initialSearchParams) {
return out
}
for (const [key, value] of initialSearchParams) {
out.set(key, value)
}
return out
} else {
return new URLSearchParams(location.search)
}
})

React.useLayoutEffect(
() => subscribeToQueryUpdates(({ search }) => setSearch(search)),
[]
)
const qs = search.toString()

return (
<pre
aria-label="Querystring spy"
aria-description="For browsers where the query is hard to see (eg: on mobile)"
style={{
padding: '4px 6px',
border: 'solid 1px gray',
borderRadius: '4px',
overflow: 'auto'
}}
>
{Boolean(qs) && <>?{qs}</>}
{!qs && <span style={{ fontStyle: 'italic' }}>{'<empty query>'}</span>}
</pre>
)
}
37 changes: 37 additions & 0 deletions packages/e2e/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
// Type checking
"strict": true,
"alwaysStrict": false, // Don't emit "use strict" to avoid conflicts with "use client"
// Modules
"module": "ESNext",
"moduleResolution": "node",
"resolveJsonModule": true,
// Language & Environment
"target": "ESNext",
"lib": ["DOM", "DOM.Iterable", "ESNext"],
// Emit
"noEmit": true,
"declaration": false,
"downlevelIteration": true,
"jsx": "preserve",
// Interop
"allowJs": true,
"isolatedModules": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
// Misc
"skipLibCheck": true,
"skipDefaultLibCheck": true,
"incremental": true,
"tsBuildInfoFile": ".next/cache/.tsbuildinfo",
"plugins": [
{
"name": "next"
}
]
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
10 changes: 2 additions & 8 deletions packages/playground/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "next-usequerystate-playground",
"name": "playground",
"version": "0.0.0-internal",
"description": "Examples and demos for next-usequerystate",
"license": "MIT",
Expand All @@ -13,11 +13,7 @@
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"pretest": "cypress install",
"test": "run-p --race start cypress:run",
"cypress:open": "cypress open",
"cypress:run": "cypress run --headless"
"start": "next start"
},
"dependencies": {
"next": "^14",
Expand All @@ -30,8 +26,6 @@
"@types/react": "^18.2.33",
"@types/react-dom": "^18.2.14",
"@types/webpack": "^5.28.4",
"cypress": "^13.3.3",
"npm-run-all": "^4.1.5",
"typescript": "^5.2.2"
}
}
Loading

0 comments on commit 366e394

Please sign in to comment.