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

Split e2e and playground #390

Merged
merged 14 commits into from
Nov 9, 2023
23 changes: 17 additions & 6 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,19 @@ env:

jobs:
ci:
name: Integration
name: Integration (Next.js ${{ matrix.next-version }}${{ matrix.base-path != '/' && ' with basePath' || ''}})
runs-on: ubuntu-latest
strategy:
matrix:
base-path: ['/']
next-version:
- '13.4'
- '13.5'
- '14'
- latest
include:
- next-version: 'latest'
base-path: '/base'
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- uses: pnpm/action-setup@d882d12c64e032187b2edb46d3a0d003b7a43598
Expand All @@ -23,19 +34,20 @@ jobs:
cache: pnpm
- name: Install dependencies
run: pnpm install
- name: Install Next.js version ${{ matrix.next-version }}
run: pnpm add --filter e2e next@${{ matrix.next-version }}
- name: Run integration tests
run: pnpm run ci
run: pnpm run test
env:
BASE_PATH: ${{ matrix.base-path }}
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()
with:
status: ${{ job.status }}
jobName: next@${{ matrix.next-version }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

Expand Down Expand Up @@ -65,4 +77,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
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
"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",
"prepare": "husky install"
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { defineConfig } from 'cypress'

const basePath = process.env.BASE_PATH === '/' ? '' : process.env.BASE_PATH

export default defineConfig({
e2e: {
baseUrl: `http://localhost:3000`,
baseUrl: `http://localhost:3001${basePath}`,
video: false,
fixturesFolder: false,
supportFile: false,
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

it('Reproduction for issue #388', () => {
cy.config('retries', 0)
cy.visit('/e2e/app/repro-388')
cy.visit('/app/repro-388')
cy.contains('#hydration-marker', 'hydrated').should('be.hidden')

cy.get('#start').click()
Expand All @@ -18,7 +18,7 @@ it('Reproduction for issue #388', () => {
cy.get('#counter').should('have.text', 'Counter: 1')

// Reset the page
cy.visit('/e2e/app/repro-388')
cy.visit('/app/repro-388')
cy.get('#start').click()
// The URL should have a ?counter=1 query string
cy.location('search').should('eq', '?counter=1')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,24 +87,24 @@ function runTest() {

describe('useQueryState (app router)', () => {
it('works in standard routes', () => {
cy.visit('/e2e/app/useQueryState')
cy.visit('/app/useQueryState')
runTest()
})

it('works in dynamic routes', () => {
cy.visit('/e2e/app/useQueryState/dynamic/route')
cy.visit('/app/useQueryState/dynamic/route')
runTest()
})
})

describe('useQueryState (pages router)', () => {
it('works in standard routes', () => {
cy.visit('/e2e/pages/useQueryState')
cy.visit('/pages/useQueryState')
runTest()
})

it('works in dynamic routes', () => {
cy.visit('/e2e/pages/useQueryState/dynamic/route')
cy.visit('/pages/useQueryState/dynamic/route')
runTest()
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -77,24 +77,24 @@ function runTest() {

describe('useQueryStates (app router)', () => {
it('uses string by default', () => {
cy.visit('/e2e/app/useQueryStates')
cy.visit('/app/useQueryStates')
runTest()
})

it('should work with dynamic routes', () => {
cy.visit('/e2e/app/useQueryStates/dynamic/route')
cy.visit('/app/useQueryStates/dynamic/route')
runTest()
})
})

describe('useQueryStates (pages router)', () => {
it('uses string by default', () => {
cy.visit('/e2e/pages/useQueryStates')
cy.visit('/pages/useQueryStates')
runTest()
})

it('should work with dynamic routes', () => {
cy.visit('/e2e/pages/useQueryStates/dynamic/route')
cy.visit('/pages/useQueryStates/dynamic/route')
runTest()
})
})
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.
6 changes: 6 additions & 0 deletions packages/e2e/next.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/** @type {import('next').NextConfig } */
const config = {
basePath: process.env.BASE_PATH === '/' ? undefined : process.env.BASE_PATH
}

export default config
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.0.2-canary.7",
"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"
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
'use client'

import { parseAsInteger, useQueryState } from 'next-usequerystate'
import { PrefetchKind } from 'next/dist/client/components/router-reducer/router-reducer-types'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import React from 'react'

export default function Page() {
const router = useRouter()
const [counter, setCounter] = useQueryState(
'counter',
parseAsInteger.withDefault(0)
)
const [mounted, setMounted] = React.useState(false)
const manualPrefetch = React.useCallback(() => {
router.prefetch('/', { kind: PrefetchKind.FULL })
}, [router])

return (
<>
<button id="start" onClick={() => setCounter(1)}>
Start
</button>
<button id="start" onClick={() => manualPrefetch()}>
Manual prefetch
</button>
<>
<p>
The counter is set but only in the History API, the Next.js router
Expand All @@ -42,7 +51,7 @@ export default function Page() {
</Link>
{mounted && (
<Link
href="/e2e/app/useQueryState"
href="/app/useQueryState"
style={{
display: 'inline-block',
paddingInline: '1rem',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const RoutingTourView: React.FC<RoutingTourViewProps> = ({
return (
<>
<Link
href={`/e2e/app/routing-tour/${nextPage}?from=${thisPage}&counter=${
href={`/app/routing-tour/${nextPage}?from=${thisPage}&counter=${
counter + 1
}`}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@ export default function ServerStartPage() {
return (
<ul>
<li>
<Link href="/e2e/app/routing-tour/a?from=start.client">
<Link href="/app/routing-tour/a?from=start.client">
a (server, prefetch)
</Link>
</li>
<li>
<Link href="/e2e/app/routing-tour/b?from=start.client" prefetch={false}>
<Link href="/app/routing-tour/b?from=start.client" prefetch={false}>
b (server, no prefetch)
</Link>
</li>
<li>
<Link href="/e2e/app/routing-tour/c?from=start.client">
<Link href="/app/routing-tour/c?from=start.client">
c (client, prefetch)
</Link>
</li>
<li>
<Link href="/e2e/app/routing-tour/d?from=start.client" prefetch={false}>
<Link href="/app/routing-tour/d?from=start.client" prefetch={false}>
d (client, no prefetch)
</Link>
</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@ export default function ServerStartPage() {
return (
<ul>
<li>
<Link href="/e2e/app/routing-tour/a?from=start.server">
<Link href="/app/routing-tour/a?from=start.server">
a (server, prefetch)
</Link>
</li>
<li>
<Link href="/e2e/app/routing-tour/b?from=start.server" prefetch={false}>
<Link href="/app/routing-tour/b?from=start.server" prefetch={false}>
b (server, no prefetch)
</Link>
</li>
<li>
<Link href="/e2e/app/routing-tour/c?from=start.server">
<Link href="/app/routing-tour/c?from=start.server">
c (client, prefetch)
</Link>
</li>
<li>
<Link href="/e2e/app/routing-tour/d?from=start.server" prefetch={false}>
<Link href="/app/routing-tour/d?from=start.server" prefetch={false}>
d (client, no prefetch)
</Link>
</li>
Expand Down
25 changes: 25 additions & 0 deletions packages/e2e/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
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>
{children}
</body>
</html>
)
}
Loading
Loading