Skip to content

Commit

Permalink
feat(pilot-app): load route state through URL param (#480)
Browse files Browse the repository at this point in the history
* define route schema

* chore: start test setup for app

* chore: start pulling shared types into schema package

* move more creator methods

* start extending test-utils to cater for framework use-case of react-router

* use new methods in app

* update imports after chains package has been created

* get type setup in order for app

* revert some changes; make test work; break app

* remove unused code

* remove noExternal flag

* make tests run again

* add nodejs compat

* run app tests in pipeline

* enable coverage report for app tests

* also use styles from ui pcakage
  • Loading branch information
frontendphil authored Jan 9, 2025
1 parent fb6c75f commit 1d7c86c
Show file tree
Hide file tree
Showing 70 changed files with 786 additions and 209 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/app-preview.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Deploy Pilot App
name: Pilot App

on:
pull_request:
Expand Down
37 changes: 31 additions & 6 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,35 @@ jobs:
cache-dependency-path: '**/pnpm-lock.yaml'
- run: pnpm install --prefer-offline
- run: pnpm test
- name: 'Report Coverage'
# Set if: always() to also generate the report if tests are failing
# Only works if you set `reportOnFailure: true` in your vite config as specified above
if: always()
uses: davelosert/vitest-coverage-report-action@v2

test-utils:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./packages/test-utils
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: latest
cache: 'pnpm'
cache-dependency-path: '**/pnpm-lock.yaml'
- run: pnpm install --prefer-offline
- run: pnpm test

pilot-app:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./deployables/app
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
working-directory: packages/ui
node-version: latest
cache: 'pnpm'
cache-dependency-path: '**/pnpm-lock.yaml'
- run: pnpm install --prefer-offline
- run: pnpm test
2 changes: 0 additions & 2 deletions deployables/app/app/entry.server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { renderToReadableStream } from 'react-dom/server'
import type { AppLoadContext, EntryContext } from 'react-router'
import { ServerRouter } from 'react-router'

const ABORT_DELAY = 5_000

export default async function handleRequest(
request: Request,
responseStatusCode: number,
Expand Down
4 changes: 2 additions & 2 deletions deployables/app/app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import './app.css'

export function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<html lang="en" className="h-full overflow-hidden">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body>
<body className="h-full bg-gradient-to-b from-white to-zinc-50 text-base text-zinc-900 dark:from-zinc-950 dark:via-zinc-950 dark:to-gray-900 dark:text-white">
{children}
<ScrollRestoration />
<Scripts />
Expand Down
7 changes: 5 additions & 2 deletions deployables/app/app/routes.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { type RouteConfig, index } from '@react-router/dev/routes'
import { type RouteConfig, index, route } from '@react-router/dev/routes'

export default [index('routes/index.tsx')] satisfies RouteConfig
export default [
index('routes/index.tsx'),
route('/edit-route', 'routes/edit-route.tsx'),
] satisfies RouteConfig
21 changes: 21 additions & 0 deletions deployables/app/app/routes/edit-route.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { render } from '@/test-utils'
import { screen } from '@testing-library/react'
import { createMockExecutionRoute } from '@zodiac/test-utils'
import { describe, expect, it } from 'vitest'
import EditRoute, { loader } from './edit-route'

describe('Edit route', () => {
it('shows the name of a route', async () => {
const route = createMockExecutionRoute({ label: 'Test route' })

await render<typeof import('./edit-route')>(
'/edit-route',
{ path: '/edit-route', Component: EditRoute, loader },
{ searchParams: { route: btoa(JSON.stringify(route)) } },
)

expect(screen.getByRole('textbox', { name: 'Label' })).toHaveValue(
'Test route',
)
})
})
32 changes: 32 additions & 0 deletions deployables/app/app/routes/edit-route.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { invariantResponse } from '@epic-web/invariant'
import { executionRouteSchema } from '@zodiac/schema'
import { TextInput } from '@zodiac/ui'
import type { Route } from './+types/edit-route'

export const loader = ({ request }: Route.LoaderArgs) => {
const url = new URL(request.url)

const routeData = url.searchParams.get('route')

invariantResponse(routeData != null, 'Missing "route" parameter')

const decodedData = Buffer.from(routeData, 'base64')

try {
const rawJson = JSON.parse(decodedData.toString())

return { route: executionRouteSchema.parse(rawJson) }
} catch {
throw new Response(null, { status: 400 })
}
}

const EditRoute = ({ loaderData }: Route.ComponentProps) => {
return (
<>
<TextInput label="Label" defaultValue={loaderData.route.label} />
</>
)
}

export default EditRoute
16 changes: 14 additions & 2 deletions deployables/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,41 @@
"build": "react-router build",
"dev": "react-router dev",
"start": "wrangler dev",
"check-types": "react-router typegen && tsc -b"
"check-types": "react-router typegen && tsc -b",
"test": "vitest"
},
"dependencies": {
"@epic-web/invariant": "^1.0.0",
"@react-router/node": "^7.1.1",
"@react-router/serve": "^7.1.1",
"@zodiac/schema": "workspace:*",
"@zodiac/ui": "workspace:*",
"isbot": "^5.1.17",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-router": "^7.1.1"
"react-router": "^7.1.1",
"zod": "^3.23.8"
},
"devDependencies": {
"@cloudflare/workers-types": "4.20241230.0",
"@hiogawa/vite-node-miniflare": "0.1.1",
"@react-router/dev": "^7.1.1",
"@testing-library/jest-dom": "^6.4.6",
"@testing-library/react": "^16.0.1",
"@testing-library/user-event": "14.5.2",
"@types/node": "^22.0.0",
"@types/react": "^19.0.1",
"@types/react-dom": "^19.0.1",
"@vitest/coverage-v8": "2.1.8",
"@zodiac/test-utils": "workspace:*",
"autoprefixer": "^10.4.20",
"eslint": "^9.7.0",
"postcss": "^8.4.49",
"tailwindcss": "^3.4.16",
"typescript": "^5.7.2",
"vite": "^5.4.11",
"vite-tsconfig-paths": "^5.1.4",
"vitest": "2.1.8",
"wrangler": "^3.87.0"
}
}
5 changes: 4 additions & 1 deletion deployables/app/tailwind.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import type { Config } from 'tailwindcss'

export default {
content: ['./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}'],
content: [
'./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}',
'../../packages/ui/**/*.tsx',
],
theme: {
extend: {
fontFamily: {
Expand Down
1 change: 1 addition & 0 deletions deployables/app/test-utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { render } from './render'
14 changes: 14 additions & 0 deletions deployables/app/test-utils/render.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {
renderFramework,
type FrameworkRoute,
type RenderOptions,
type RouteModule,
} from '@zodiac/test-utils'

export function render<Module extends RouteModule>(
currentPath: string,
route: FrameworkRoute<Module>,
options: RenderOptions,
) {
return renderFramework(currentPath, route, options)
}
7 changes: 5 additions & 2 deletions deployables/app/tsconfig.cloudflare.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
"extends": "./tsconfig.json",
"include": [
".react-router/types/**/*",
"vitest.setup.ts",
"app/**/*",
"app/**/.server/**/*",
"app/**/.client/**/*",
"workers/**/*"
"workers/**/*",
"test-utils/**/*"
],
"compilerOptions": {
"composite": true,
Expand All @@ -19,7 +21,8 @@
"baseUrl": ".",
"rootDirs": [".", "./.react-router/types"],
"paths": {
"~/*": ["./app/*"]
"~/*": ["./app/*"],
"@/test-utils": ["./test-utils/index.ts"]
},
"esModuleInterop": true,
"resolveJsonModule": true
Expand Down
5 changes: 4 additions & 1 deletion deployables/app/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
"verbatimModuleSyntax": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true
"noEmit": true,
"paths": {
"@/test-utils": ["./test-utils/index.ts"]
}
}
}
19 changes: 10 additions & 9 deletions deployables/app/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { vitePluginViteNodeMiniflare } from '@hiogawa/vite-node-miniflare'
import { reactRouter } from '@react-router/dev/vite'
import { cloudflareDevProxy } from '@react-router/dev/vite/cloudflare'
import autoprefixer from 'autoprefixer'
import tailwindcss from 'tailwindcss'
import { defineConfig } from 'vite'
Expand All @@ -20,7 +20,7 @@ export default defineConfig(({ isSsrBuild }) => ({
},
ssr: {
target: 'webworker',
noExternal: true,
// noExternal: true,
resolve: {
conditions: ['workerd', 'browser'],
},
Expand All @@ -36,13 +36,14 @@ export default defineConfig(({ isSsrBuild }) => ({
},
},
plugins: [
vitePluginViteNodeMiniflare({
entry: './workers/app.ts',
miniflareOptions: (options) => {
options.compatibilityDate = '2024-11-18'
options.compatibilityFlags = ['nodejs_compat']
},
}),
cloudflareDevProxy(),
// vitePluginViteNodeMiniflare({
// entry: './workers/app.ts',
// miniflareOptions: (options) => {
// options.compatibilityDate = '2024-11-18'
// options.compatibilityFlags = ['nodejs_compat']
// },
// }),
reactRouter(),
tsconfigPaths(),
],
Expand Down
35 changes: 35 additions & 0 deletions deployables/app/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/// <reference types="vitest" />

import { fileURLToPath } from 'url'
import { defineConfig } from 'vitest/config'
import tsConfig from './tsconfig.json'

const alias = Object.entries(tsConfig.compilerOptions.paths).reduce(
(result, [key, value]) => ({
...result,
[key]: fileURLToPath(new URL(value[0], import.meta.url)),
}),
{},
)

const { CI } = process.env

export default defineConfig({
test: {
alias,
environment: 'happy-dom',
setupFiles: ['./vitest.setup.ts'],
include: ['./app/**/*.{spec,test}.{ts,tsx}'],
mockReset: true,
clearMocks: true,

coverage: {
skipFull: true,
enabled: CI != null,
reportOnFailure: CI != null,
reporter: CI ? ['json', 'json-summary'] : undefined,
include: ['**/app/**/*.{ts,tsx}'],
exclude: ['**/src/**/*.spec.{ts,tsx}'],
},
},
})
1 change: 1 addition & 0 deletions deployables/app/vitest.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import '@testing-library/jest-dom/vitest'
8 changes: 2 additions & 6 deletions deployables/app/workers/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ declare global {
}

declare module 'react-router' {
export interface AppLoadContext {
VALUE_FROM_CLOUDFLARE: string
}
export interface AppLoadContext {}
}

const requestHandler = createRequestHandler(
Expand All @@ -18,8 +16,6 @@ const requestHandler = createRequestHandler(

export default {
fetch(request, env) {
return requestHandler(request, {
VALUE_FROM_CLOUDFLARE: 'Hello from Cloudflare',
})
return requestHandler(request)
},
} satisfies ExportedHandler<CloudflareEnvironment>
1 change: 1 addition & 0 deletions deployables/app/wrangler.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
workers_dev = true
name = "pilot-app"
compatibility_date = "2024-11-18"
compatibility_flags = ["nodejs_compat"]
main = "./build/server/index.js"
assets = { directory = "./build/client/" }

Expand Down
4 changes: 3 additions & 1 deletion deployables/extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@
"react-router": "7.1.1",
"react-stick": "^5.0.6",
"zod": "^3.23.8",
"@zodiac/ui": "workspace:*"
"@zodiac/ui": "workspace:*",
"@zodiac/schema": "workspace:*",
"@zodiac/chains": "workspace:*"
}
}
Loading

0 comments on commit 1d7c86c

Please sign in to comment.