Skip to content
Open
Show file tree
Hide file tree
Changes from 6 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
27 changes: 27 additions & 0 deletions .github/workflows/playwright.yml
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add this as another job to the Frontend CI?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bump on this?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check.

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Playwright Tests
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
Comment thread
HarK-github marked this conversation as resolved.
Outdated
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Comment thread
patzielinski marked this conversation as resolved.
Outdated
- uses: actions/setup-node@v4
with:
node-version: lts/*
Comment thread
HarK-github marked this conversation as resolved.
Outdated
- name: Install dependencies
run: npm ci
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this line for?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is for uploading the test reports. In this case it will upload and store tests reports regardless of whether if it fails or pass.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but why is there the if statement?

with:
name: playwright-report
path: playwright-report/
retention-days: 30
9 changes: 8 additions & 1 deletion frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,11 @@ yarn-error.log*
*.tsbuildinfo
next-env.d.ts

.DS_Store
.DS_Store

# Playwright
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
/playwright/.auth/
7 changes: 6 additions & 1 deletion frontend/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export default function Home() {
} = useGittufExplorer()

return (
<main className="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-50">
<main className="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-50" data-testid="homepage-container">
<div className="max-w-7xl mx-auto p-4 md:p-8">
<Header
currentRepository={currentRepository}
Expand Down Expand Up @@ -98,6 +98,7 @@ export default function Home() {
<TabsList className="mb-6 bg-white/80 backdrop-blur-sm p-1 rounded-lg shadow-sm">
<TabsTrigger
value="commits"
data-testid="tab-commits"
className="flex items-center data-[state=active]:bg-blue-500 data-[state=active]:text-white"
>
<GitCommit className="h-4 w-4 mr-2" />
Expand All @@ -106,6 +107,7 @@ export default function Home() {
<TabsTrigger
value="visualization"
disabled={!selectedCommit}
data-testid="tab-visualization"
className="flex items-center data-[state=active]:bg-green-500 data-[state=active]:text-white"
>
<FileJson className="h-4 w-4 mr-2" />
Expand All @@ -114,6 +116,7 @@ export default function Home() {
<TabsTrigger
value="tree"
disabled={!selectedCommit}
data-testid="tab-tree"
className="flex items-center data-[state=active]:bg-purple-500 data-[state=active]:text-white"
>
<FileJson className="h-4 w-4 mr-2" />
Expand All @@ -122,6 +125,7 @@ export default function Home() {
<TabsTrigger
value="compare"
disabled={!compareCommits.base || !compareCommits.compare}
data-testid="tab-compare"
className="flex items-center data-[state=active]:bg-orange-500 data-[state=active]:text-white"
>
<GitCompare className="h-4 w-4 mr-2" />
Expand All @@ -130,6 +134,7 @@ export default function Home() {
<TabsTrigger
value="analysis"
disabled={selectedCommits.length < 2}
data-testid="tab-analysis"
className="flex items-center data-[state=active]:bg-indigo-500 data-[state=active]:text-white"
>
<BarChart3 className="h-4 w-4 mr-2" />
Expand Down
17 changes: 12 additions & 5 deletions frontend/app/simulator/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ export default function SimulatorPage() {

return (
<div
data-testid="homepage-container"
className={`min-h-screen transition-colors duration-300 ${
darkMode ? "bg-gray-900 text-white" : "bg-gradient-to-br from-blue-50 via-indigo-50 to-purple-50"
}`}
>
{/* Story Modal */}
<StoryModal
data-testid="story-modal"
isOpen={showStory}
onClose={() => setShowStory(false)}
fixture={fixture}
Expand All @@ -49,18 +51,23 @@ export default function SimulatorPage() {
<AnimatePresence>
{showSimulator && (
<motion.div
data-testid="simulator-content"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
className="space-y-6"
>
{/* Status Card */}
<StatusCard result={displayResult.result} reasons={displayResult.reasons} />
<StatusCard
data-testid="status-card"
result={displayResult.result}
reasons={displayResult.reasons}
/>

{/* Main Content Area */}
<div className={`grid gap-6 ${expandedGraph ? "grid-cols-1" : "grid-cols-1 lg:grid-cols-4"}`}>
<SimulatorControls state={state} />
<SimulatorGraph state={state} />
<SimulatorControls state={state} data-testid="simulator-controls"/>
<SimulatorGraph state={state} data-testid="simulator-graph" />
</div>

{/* Detailed Results */}
Expand All @@ -70,11 +77,11 @@ export default function SimulatorPage() {
</AnimatePresence>

{/* Footer Glossary */}
<SimulatorGlossary state={state} />
<SimulatorGlossary data-testid="simulator-glossary" state={state} />
</div>

{/* Custom Config Dialog */}
<SimulatorConfigModal state={state} />
</div>
)
}
}
3 changes: 2 additions & 1 deletion frontend/components/features/commit/commit-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export default function CommitList({
}

return (
<div className="space-y-4">
<div className="space-y-4" data-testid="commit-list">
<div className="flex flex-col md:flex-row gap-3 items-start md:items-center">
<div className="relative flex-grow">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-slate-400 h-4 w-4" />
Expand Down Expand Up @@ -226,6 +226,7 @@ export default function CommitList({
? "bg-blue-50 border-blue-200"
: "bg-white border-slate-200 hover:border-slate-300"
}`}
data-testid="commit-item"
>
<div className="flex items-start justify-between">
{selectionMode === "range" && (
Expand Down
12 changes: 8 additions & 4 deletions frontend/components/features/json/json-diff-visualization.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ const NODE_WIDTH = 220
const NODE_HEIGHT = 80

// Animated node wrapper
const AnimatedNode = ({ children }: { children: React.ReactNode }) => {
const AnimatedNode = ({ children, testId }: { children: React.ReactNode; testId?: string }) => {
return (
<motion.div initial={{ opacity: 0, scale: 0.8 }} animate={{ opacity: 1, scale: 1 }} transition={{ duration: 0.3 }}>
<motion.div initial={{ opacity: 0, scale: 0.8 }} animate={{ opacity: 1, scale: 1 }} transition={{ duration: 0.3 }} data-testid={testId}>
{children}
</motion.div>
)
Expand Down Expand Up @@ -169,7 +169,7 @@ function DiffRootNode({ data, isConnectable }: { data: DiffNodeData; isConnectab

function DiffAddedNode({ data, isConnectable }: { data: DiffNodeData; isConnectable: boolean }) {
return (
<AnimatedNode>
<AnimatedNode testId="diff-added">
<DiffNodeTooltip data={data} type="diffAdded">
<CollapsibleCard
title={data.label || "Added"}
Expand Down Expand Up @@ -713,7 +713,9 @@ export default function JsonDiffVisualization({
}, [baseData, compareData, expandedNodes, toggleNodeExpansion, showUnchanged, setNodes, setEdges])

return (
<ReactFlow
<div data-testid="json-diff-viewer">
<div data-testid="json-diff-container">
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
Expand Down Expand Up @@ -758,5 +760,7 @@ export default function JsonDiffVisualization({
</div>
)}
</ReactFlow>
</div>
</div>
)
}
2 changes: 1 addition & 1 deletion frontend/components/features/json/json-tree-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ export default function JsonTreeView({ jsonData, viewMode = "normal" }: JsonTree
}

return (
<div className="font-mono text-sm max-h-[600px] overflow-auto">
<div className="font-mono text-sm max-h-[600px] overflow-auto" data-testid="json-tree-view">
<div className="p-4">
<TreeNode data={jsonData} viewMode={viewMode} />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ interface ValidationDetails {
}

return (
<Card className="bg-white/90 backdrop-blur-sm border-slate-200 shadow-lg">
<Card className="bg-white/90 backdrop-blur-sm border-slate-200 shadow-lg" data-testid="repository-selector">
<CardHeader className="pb-4">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-3">
Expand All @@ -152,7 +152,7 @@ interface ValidationDetails {
</div>
</div>
{currentRepository && (
<div className="text-right">
<div className="text-right" data-testid="selected-repository">
<Badge variant="outline" className="bg-green-50 text-green-700 border-green-200">
<CheckCircle className="h-3 w-3 mr-1" />
Connected
Expand All @@ -165,11 +165,11 @@ interface ValidationDetails {
<CardContent className="space-y-6">
<Tabs value={activeTab} onValueChange={(value) => setActiveTab(value as "remote" | "local")}>
<TabsList className="grid w-full grid-cols-2">
<TabsTrigger value="remote" className="flex items-center">
<TabsTrigger value="remote" className="flex items-center" data-testid="repository-option">
<Globe className="h-4 w-4 mr-2" />
Remote Repository
</TabsTrigger>
<TabsTrigger value="local" className="flex items-center">
<TabsTrigger value="local" className="flex items-center" data-testid="repository-option">
<HardDrive className="h-4 w-4 mr-2" />
Local Repository
</TabsTrigger>
Expand Down Expand Up @@ -229,6 +229,7 @@ interface ValidationDetails {
onClick={handleTryDemo}
disabled={isLoading}
className="text-blue-600 border-blue-200 hover:bg-blue-50 bg-transparent"
data-testid="try-demo-button"
>
Try Demo
</Button>
Expand Down
7 changes: 4 additions & 3 deletions frontend/components/features/simulator/simulator-controls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ import type { SimulatorState } from "@/hooks/use-gittuf-simulator"

interface SimulatorControlsProps {
state: SimulatorState
"data-testid"?: string
}

export function SimulatorControls({ state }: SimulatorControlsProps) {
const {
export function SimulatorControls({ state, "data-testid": testId }: SimulatorControlsProps) {
const {
expandedGraph,
showControls,
setShowControls,
Expand All @@ -33,7 +34,7 @@ export function SimulatorControls({ state }: SimulatorControlsProps) {
if (expandedGraph) return null

return (
<motion.div initial={{ opacity: 0, x: -20 }} animate={{ opacity: 1, x: 0 }} className="lg:col-span-1 space-y-4">
<motion.div initial={{ opacity: 0, x: -20 }} animate={{ opacity: 1, x: 0 }} className="lg:col-span-1 space-y-4" data-testid={testId}>
<Card className={darkMode ? "bg-gray-800 border-gray-700" : "bg-white"}>
<CardHeader className="pb-3">
<div className="flex items-center justify-between">
Expand Down
21 changes: 14 additions & 7 deletions frontend/components/features/simulator/simulator-glossary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,49 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import type { SimulatorState } from "@/hooks/use-gittuf-simulator"

interface SimulatorGlossaryProps {
"data-testid"?: string // Added for E2E testing
state: SimulatorState
}

export function SimulatorGlossary({ state }: SimulatorGlossaryProps) {
export function SimulatorGlossary({ "data-testid": testId, state }: SimulatorGlossaryProps) {
const { darkMode } = state

return (
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ delay: 0.5 }} className="mt-12">
<motion.div
data-testid={testId} // Added for E2E testing
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.5 }}
className="mt-12"
>
<Card className={`${darkMode ? "bg-gray-800 border-gray-700" : "bg-white"} border-t-4 border-t-blue-500`}>
<CardHeader>
<CardTitle className="text-sm">Glossary</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 text-sm">
<div>
<div data-testid="glossary-item-root">
<h4 className="font-semibold mb-1 flex items-center gap-1">
<Crown className="w-3 h-3" />
Root
</h4>
<p className="text-gray-600 text-xs">The ultimate authority that can delegate permissions</p>
</div>
<div>
<div data-testid="glossary-item-role">
<h4 className="font-semibold mb-1 flex items-center gap-1">
<Shield className="w-3 h-3" />
Role
</h4>
<p className="text-gray-600 text-xs">A permission set that protects specific files or operations</p>
</div>
<div>
<div data-testid="glossary-item-attestation">
<h4 className="font-semibold mb-1 flex items-center gap-1">
<FileText className="w-3 h-3" />
Attestation
</h4>
<p className="text-gray-600 text-xs">A signed approval tied to a specific change</p>
</div>
<div>
<div data-testid="glossary-item-threshold">
<h4 className="font-semibold mb-1 flex items-center gap-1">
<Users className="w-3 h-3" />
Threshold
Expand All @@ -53,4 +60,4 @@ export function SimulatorGlossary({ state }: SimulatorGlossaryProps) {
</Card>
</motion.div>
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export function SimulatorHeader({ state }: SimulatorHeaderProps) {
disabled={isProcessing}
className="bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700"
size="lg"
data-testid="simulator-play"
>
{isProcessing ? (
<>
Expand Down
1 change: 1 addition & 0 deletions frontend/components/features/visualization/trust-graph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,7 @@ export function TrustGraph({
<div
key={graphKey}
className={`relative w-full h-full bg-gradient-to-br from-gray-50 to-gray-100 rounded-lg border-2 border-gray-200 overflow-hidden ${className}`}
data-testid="trust-graph"
>
{/* Loading overlay */}
{isLoading && (
Expand Down
Loading