diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8dbae9e1..e29d78bd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -120,6 +120,48 @@ jobs: bash compose.sh -- logs git-proxy-java fi + playwright-test: + name: Playwright UI Tests + runs-on: ubuntu-latest + if: > + github.ref == 'refs/heads/main' || + github.event_name == 'pull_request' + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6 + + - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # ratchet:actions/setup-java@v5 + with: + distribution: temurin + java-version: 25 + cache: gradle + + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # ratchet:actions/setup-node@v6 + with: + node-version: '24.15.0' + cache: npm + cache-dependency-path: git-proxy-java-dashboard/frontend/package-lock.json + + - name: Install frontend dependencies + run: npm ci + working-directory: git-proxy-java-dashboard/frontend + + - name: Install Playwright browsers + run: npx playwright install --with-deps chromium + working-directory: git-proxy-java-dashboard/frontend + + - name: Run Playwright tests + run: npm run test:e2e + working-directory: git-proxy-java-dashboard/frontend + + - name: Upload Playwright report + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # ratchet:actions/upload-artifact@v7 + with: + name: playwright-report + path: git-proxy-java-dashboard/frontend/playwright-report/ + retention-days: 14 + dependency-submission: name: Dependency Submission runs-on: ubuntu-latest diff --git a/git-proxy-java-dashboard/frontend/.gitignore b/git-proxy-java-dashboard/frontend/.gitignore index 7dc978b3..520fbd36 100644 --- a/git-proxy-java-dashboard/frontend/.gitignore +++ b/git-proxy-java-dashboard/frontend/.gitignore @@ -30,6 +30,11 @@ vite.config.ts.timestamp-* # Local env overrides *.local +# Playwright +/test-results/ +/playwright-report/ +/tests/.auth/ + # Editor directories and files .vscode/* !.vscode/extensions.json diff --git a/git-proxy-java-dashboard/frontend/package-lock.json b/git-proxy-java-dashboard/frontend/package-lock.json index 29869d06..1b8d5b20 100644 --- a/git-proxy-java-dashboard/frontend/package-lock.json +++ b/git-proxy-java-dashboard/frontend/package-lock.json @@ -15,6 +15,7 @@ }, "devDependencies": { "@eslint/js": "^9.39.4", + "@playwright/test": "^1.49.0", "@tailwindcss/vite": "^4.2.2", "@types/node": "^24.12.0", "@types/react": "^19.2.14", @@ -593,6 +594,22 @@ "url": "https://github.com/sponsors/Boshen" } }, + "node_modules/@playwright/test": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.60.0.tgz", + "integrity": "sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.60.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@profoundlogic/hogan": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@profoundlogic/hogan/-/hogan-3.0.4.tgz", @@ -2980,6 +2997,53 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/playwright": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz", + "integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.60.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz", + "integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/postcss": { "version": "8.5.14", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", diff --git a/git-proxy-java-dashboard/frontend/package.json b/git-proxy-java-dashboard/frontend/package.json index e3b85976..b2a2a8e1 100644 --- a/git-proxy-java-dashboard/frontend/package.json +++ b/git-proxy-java-dashboard/frontend/package.json @@ -9,7 +9,8 @@ "lint": "eslint .", "format": "prettier --write src", "format:check": "prettier --check src", - "preview": "vite preview" + "preview": "vite preview", + "test:e2e": "playwright test" }, "dependencies": { "diff2html": "^3.4.56", @@ -32,6 +33,7 @@ "typescript": "~5.9.3", "typescript-eslint": "^8.57.0", "vite": "^8.0.1", - "prettier": "^3.5.3" + "prettier": "^3.5.3", + "@playwright/test": "^1.49.0" } } diff --git a/git-proxy-java-dashboard/frontend/playwright.config.ts b/git-proxy-java-dashboard/frontend/playwright.config.ts new file mode 100644 index 00000000..6e6417cd --- /dev/null +++ b/git-proxy-java-dashboard/frontend/playwright.config.ts @@ -0,0 +1,30 @@ +import { defineConfig, devices } from '@playwright/test' + +export default defineConfig({ + testDir: './tests', + use: { + baseURL: 'http://localhost:8080', + trace: 'on-first-retry', + }, + webServer: { + command: 'GITPROXY_DATABASE_TYPE=h2-mem ./gradlew :git-proxy-java-dashboard:run', + cwd: '../../', + url: 'http://localhost:8080/api/health', + timeout: 120_000, + reuseExistingServer: !process.env.CI, + }, + projects: [ + { + name: 'setup', + testMatch: /auth\.setup\.ts/, + }, + { + name: 'chromium', + use: { + ...devices['Desktop Chrome'], + storageState: 'tests/.auth/admin.json', + }, + dependencies: ['setup'], + }, + ], +}) diff --git a/git-proxy-java-dashboard/frontend/src/api.ts b/git-proxy-java-dashboard/frontend/src/api.ts index 1c3e5bd4..0f2bfc48 100644 --- a/git-proxy-java-dashboard/frontend/src/api.ts +++ b/git-proxy-java-dashboard/frontend/src/api.ts @@ -237,7 +237,7 @@ export async function fetchUserPermissions(username: string) { export async function addUserPermission( username: string, - data: { provider: string; path: string; pathType: string; operations: string }, + data: { provider: string; value: string; matchType: string; operations: string }, ) { const res = await apiFetch(`/api/users/${encodeURIComponent(username)}/permissions`, { method: 'POST', diff --git a/git-proxy-java-dashboard/frontend/src/components/PermissionBadges.tsx b/git-proxy-java-dashboard/frontend/src/components/PermissionBadges.tsx index 9040a139..300e7591 100644 --- a/git-proxy-java-dashboard/frontend/src/components/PermissionBadges.tsx +++ b/git-proxy-java-dashboard/frontend/src/components/PermissionBadges.tsx @@ -1,6 +1,6 @@ import type { RepoPermission } from '../types' -export function PathTypeBadge({ pathType }: { pathType: RepoPermission['pathType'] }) { +export function PathTypeBadge({ matchType }: { matchType: RepoPermission['matchType'] }) { const styles = { LITERAL: 'bg-gray-100 text-gray-600', GLOB: 'bg-purple-50 text-purple-700', @@ -8,9 +8,9 @@ export function PathTypeBadge({ pathType }: { pathType: RepoPermission['pathType } return ( - {pathType.toLowerCase()} + {matchType.toLowerCase()} ) } diff --git a/git-proxy-java-dashboard/frontend/src/pages/Profile.tsx b/git-proxy-java-dashboard/frontend/src/pages/Profile.tsx index 16f94355..af8db53f 100644 --- a/git-proxy-java-dashboard/frontend/src/pages/Profile.tsx +++ b/git-proxy-java-dashboard/frontend/src/pages/Profile.tsx @@ -275,9 +275,9 @@ export function Profile() {
- {stripAnsi(s.content)}
+ {[s.errorMessage ?? s.blockedMessage, s.content]
+ .filter(Boolean)
+ .join('\n\n')}
)}
diff --git a/git-proxy-java-dashboard/frontend/src/pages/UserDetail.tsx b/git-proxy-java-dashboard/frontend/src/pages/UserDetail.tsx
index e7dabd4e..f8103479 100644
--- a/git-proxy-java-dashboard/frontend/src/pages/UserDetail.tsx
+++ b/git-proxy-java-dashboard/frontend/src/pages/UserDetail.tsx
@@ -626,8 +626,8 @@ function AddPermissionModal({
try {
await addUserPermission(username, {
provider: provider.trim(),
- path: path.trim(),
- pathType,
+ value: path.trim(),
+ matchType: pathType,
operations,
})
onAdded()
@@ -790,9 +790,9 @@ function PermissionsTab({ username, isAdmin }: { username: string; isAdmin: bool