feat: Add e2e setup and tests (#535)

This commit is contained in:
Jovan Milosevic
2025-02-12 08:57:18 +01:00
committed by GitHub
parent e00dad9200
commit 6794ab20d3
19 changed files with 366 additions and 42 deletions
+8
View File
@@ -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' })
+20
View File
@@ -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/
+13
View File
@@ -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"] }
+19
View File
@@ -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"
}
}
+26
View File
@@ -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',
},
})
+17
View File
@@ -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>
)
}
+14
View File
@@ -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",
}))
}
+24
View File
@@ -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>
}
+23
View File
@@ -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')
})
+24
View File
@@ -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"]
}
+5
View File
@@ -0,0 +1,5 @@
import type { TuonoConfig } from 'tuono/config'
const config: TuonoConfig = {}
export default config