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

Enable 3d snapshot tests with playwright + vite #148

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
37 changes: 37 additions & 0 deletions .github/workflows/playwright-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Created using @tscircuit/plop (npm install -g @tscircuit/plop)
name: Playwright Test

on:
push:
branches: [main]
pull_request:

jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup bun
uses: oven-sh/setup-bun@v1
with:
bun-version: latest

- name: Install dependencies
run: bun install

- name: Install Playwright browsers
run: bunx playwright install

- name: Run tests
run: bun run playwright

- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: test-results
path: test-results/
retention-days: 30
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ tmp*
*.diff.png
.env
.DS_Store
search-result.json
search-result.json
playwright-report
test-results
Binary file modified bun.lockb
Binary file not shown.
14 changes: 14 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>EasyEDA Converter</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/site/main.tsx"></script>
<script src="https://cdn.tailwindcss.com"></script>
</body>
</html>
18 changes: 15 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"url": "https://github.com/tscircuit/easyeda-converter"
},
"scripts": {
"start": "vite",
"test": "bun test",
"cli": "bun cli/main.ts",
"build": "tsup lib/index.ts cli/main.ts --format esm --dts --sourcemap",
Expand All @@ -25,14 +26,25 @@
},
"devDependencies": {
"@biomejs/biome": "^1.8.3",
"@playwright/test": "^1.49.1",
"@tscircuit/log-soup": "1.0.2",
"@tscircuit/props": "^0.0.128",
"@tscircuit/runframe": "^0.0.72",
"@tscircuit/soup-util": "^0.0.41",
"@types/bun": "latest",
"@types/react": "^19.0.4",
"@types/react-dom": "^19.0.2",
"@vitejs/plugin-react": "^4.3.4",
"bun-match-svg": "^0.0.6",
"circuit-json": "^0.0.92",
"circuit-to-svg": "^0.0.56",
"tsup": "^8.1.0"
"circuit-json": "^0.0.129",
"circuit-to-svg": "^0.0.99",
"class-variance-authority": "^0.7.1",
"playwright": "^1.49.1",
"react": "18",
"react-dom": "18",
"tsup": "^8.1.0",
"vite": "^6.0.7",
"vite-tsconfig-paths": "^5.1.4"
},
"peerDependencies": {
"typescript": "^5.5.2"
Expand Down
10 changes: 10 additions & 0 deletions playwright-tests/c14877.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { test, expect } from "@playwright/test"

test("c14877", async ({ page }) => {
await page.goto("http://localhost:5181?jlcpcb_part_number=C14877")

await page.waitForSelector("#code-content", { state: "visible" })
await page.waitForLoadState("networkidle")

await expect(page).toHaveScreenshot()
})
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { defineConfig, devices } from "@playwright/test"
import { defineConfig as defineViteConfig } from "vite"
import { createServer } from "vite"

export default defineConfig({
testDir: "./playwright-tests",
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: "html",
use: {
baseURL: "http://localhost:5181",
trace: "on-first-retry",
},
webServer: {
command: "npm run start -- --port 5181",
url: "http://localhost:5181",
reuseExistingServer: !process.env.CI,
stdout: "pipe",
stderr: "pipe",
},
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
],
})
72 changes: 72 additions & 0 deletions site/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { RunFrame } from "@tscircuit/runframe/runner"
import { useEffect, useState } from "react"
export default () => {
const params = new URLSearchParams(window.location.search)
const jlcpcb_part_number = params.get("jlcpcb_part_number")

const [error, setError] = useState<string | null>(null)
const [tscircuitCode, setTscircuitCode] = useState<string>("")

useEffect(() => {
if (!jlcpcb_part_number) {
return
}
setError(null)

fetch("/api", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ jlcpcb_part_number }),
})
.then((res) => res.json())
.then((data) => {
if (data.error) {
throw new Error(data.error)
}
setTscircuitCode(data.tscircuitCode)
})
.catch((error) => {
setError(error.message)
})
}, [jlcpcb_part_number])

if (!jlcpcb_part_number) {
return (
<div>No part number provided, add ?jlcpcb_part_number= to the URL</div>
)
}

if (!tscircuitCode) {
return <div>Loading...</div>
}

return (
<div>
<RunFrame
defaultActiveTab="cad"
entrypoint="entrypoint.tsx"
fsMap={{
"entrypoint.tsx": `
import * as Snippet from "./snippet.tsx"

let bestImport = Object.keys(Snippet).find((key) => !key.startsWith("use"))

const Component = Snippet[bestImport]

circuit.add(<board width="10mm" height="10mm"><Component name="U1" /></board>)

`,
"snippet.tsx": tscircuitCode,
}}
/>
<pre
id="code-content"
className="bg-gray-100 p-4 rounded-lg overflow-x-auto"
>
<code className="text-sm font-mono">{tscircuitCode}</code>
</pre>
</div>
)
}
9 changes: 9 additions & 0 deletions site/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react"
import ReactDOM from "react-dom/client"
import App from "./App"

ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
},
"exclude": ["vite.config.ts"]
}
49 changes: 49 additions & 0 deletions vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { defineConfig } from "vite"
import react from "@vitejs/plugin-react"
import tsconfigPaths from "vite-tsconfig-paths"
import type { Plugin } from "vite"
import { fetchEasyEDAComponent, convertRawEasyEdaToTs } from "./dist/lib/index"

// Create plugin to handle JLCPCB part number requests
const jlcpcbPlugin = (): Plugin => ({
name: "jlcpcb-api",
configureServer(server) {
server.middlewares.use(async (req, res, next) => {
if (req.url === "/api" && req.method === "POST") {
try {
const chunks = []
for await (const chunk of req) {
chunks.push(chunk)
}
const body = JSON.parse(Buffer.concat(chunks).toString())

if (!body.jlcpcb_part_number) {
res.statusCode = 400
res.end(JSON.stringify({ error: "Missing jlcpcb_part_number" }))
return
}

const rawEasyJson = await fetchEasyEDAComponent(
body.jlcpcb_part_number,
)
const tsxComponent = await convertRawEasyEdaToTs(rawEasyJson)

res.setHeader("Content-Type", "application/json")
res.end(JSON.stringify({ tscircuitCode: tsxComponent }))
} catch (error: any) {
res.statusCode = 500
res.end(JSON.stringify({ error: error.message }))
}
} else {
next()
}
})
},
})

export default defineConfig({
plugins: [react(), tsconfigPaths(), jlcpcbPlugin()],
define: {
global: "globalThis",
},
})
Loading