mirror of
https://github.com/tuono-labs/tuono
synced 2026-07-25 12:52:47 -07:00
feat: Add e2e setup and tests (#535)
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
import { execSync } from 'child_process'
|
||||
import path from 'path'
|
||||
|
||||
const __dirname = import.meta.dirname
|
||||
const rootDir = path.join(__dirname, '..')
|
||||
|
||||
execSync('cargo build --config opt-level=0', { cwd: rootDir, stdio: 'inherit' })
|
||||
execSync('turbo build', { stdio: 'inherit' })
|
||||
@@ -0,0 +1,20 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.tuono
|
||||
out
|
||||
target
|
||||
|
||||
# Playwright
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/blob-report/
|
||||
/playwright/.cache/
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "tuono-app"
|
||||
version = "0.0.1"
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "tuono"
|
||||
path = ".tuono/main.rs"
|
||||
|
||||
[dependencies]
|
||||
tuono_lib = { path = "../../../crates/tuono_lib" }
|
||||
serde = { version = "1.0.202", features = ["derive"] }
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "fixture-base",
|
||||
"type": "module",
|
||||
"description": "Basic tuono application",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"test:e2e": "playwright test"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"tuono": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^19.0.2",
|
||||
"@types/react-dom": "^19.0.2",
|
||||
"typescript": "^5.6.3"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import * as path from 'path'
|
||||
|
||||
import { defineConfig } from '@playwright/test'
|
||||
|
||||
const __dirname = import.meta.dirname
|
||||
|
||||
const tuonoDir = path.join(__dirname, '../../../', 'target', 'debug', 'tuono')
|
||||
const setupScript = path.join(__dirname, '../..', 'e2e-test-setup.js')
|
||||
|
||||
export default defineConfig({
|
||||
testDir: './tests',
|
||||
fullyParallel: true,
|
||||
forbidOnly: !!process.env.CI,
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
webServer: {
|
||||
command: `node ${setupScript} && ${tuonoDir} dev`,
|
||||
port: 3000,
|
||||
timeout: 420 * 1000,
|
||||
stdout: 'pipe',
|
||||
reuseExistingServer: false,
|
||||
},
|
||||
use: {
|
||||
baseURL: 'http://localhost:3000',
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { ReactNode, JSX } from 'react'
|
||||
import { TuonoScripts } from 'tuono'
|
||||
|
||||
interface RootLayoutProps {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export default function RootLayout({ children }: RootLayoutProps): JSX.Element {
|
||||
return (
|
||||
<html>
|
||||
<body>
|
||||
<main>{children}</main>
|
||||
<TuonoScripts />
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
use serde::Serialize;
|
||||
use tuono_lib::{Props, Request, Response};
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct MyResponse<'a> {
|
||||
subtitle: &'a str,
|
||||
}
|
||||
|
||||
#[tuono_lib::handler]
|
||||
async fn get_server_side_props(_req: Request) -> Response {
|
||||
Response::Props(Props::new(MyResponse {
|
||||
subtitle: "Subtitle received from the server",
|
||||
}))
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import type { JSX } from 'react'
|
||||
import type { TuonoProps } from 'tuono'
|
||||
import { Link } from 'tuono'
|
||||
|
||||
interface IndexProps {
|
||||
subtitle: string
|
||||
}
|
||||
|
||||
export default function IndexPage({
|
||||
data,
|
||||
isLoading,
|
||||
}: TuonoProps<IndexProps>): JSX.Element {
|
||||
if (isLoading) {
|
||||
return <h1>Loading...</h1>
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>TUONO</h1>
|
||||
<h2>{data?.subtitle}</h2>
|
||||
<Link href={'/second-route'}>Routing link</Link>)
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { JSX } from 'react'
|
||||
|
||||
export default function SecondRoute(): JSX.Element {
|
||||
return <h1>Second route</h1>
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('it renders index page', async ({ page }) => {
|
||||
await page.goto('/')
|
||||
const header = await page.textContent('h1')
|
||||
const subtitle = await page.textContent('h2')
|
||||
expect(header).toContain('TUONO')
|
||||
expect(subtitle).toContain('Subtitle received from the server')
|
||||
})
|
||||
|
||||
test('it renders second route', async ({ page }) => {
|
||||
await page.goto('/second-route')
|
||||
const header = await page.textContent('h1')
|
||||
expect(header).toContain('Second route')
|
||||
})
|
||||
|
||||
test('it routes to second route on link click', async ({ page }) => {
|
||||
await page.goto('/')
|
||||
await page.click('text=Routing link')
|
||||
await page.waitForURL('/second-route')
|
||||
const header = await page.textContent('h1')
|
||||
expect(header).toContain('Second route')
|
||||
})
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src", "tuono.config.ts"]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { TuonoConfig } from 'tuono/config'
|
||||
|
||||
const config: TuonoConfig = {}
|
||||
|
||||
export default config
|
||||
Reference in New Issue
Block a user