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

feat(pilot-app): load route state through URL param #480

Merged
merged 16 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading