2026.06.04 frontend építés közben

This commit is contained in:
Roo
2026-06-04 07:26:22 +00:00
parent 7adf6cc3e3
commit 59a30ac428
3302 changed files with 24091 additions and 1771 deletions

View File

@@ -1,61 +0,0 @@
import { test, expect } from '@playwright/test';
// Use internal Docker network hostname for frontend
const FRONTEND_URL = 'http://sf_public_frontend:5173';
// Test user credentials (should be a valid test user in the dev database)
const TEST_EMAIL = 'superadmin@profibot.hu';
const TEST_PASSWORD = 'anypassword';
test.describe('Frontend UI E2E Flow', () => {
test('should login, select profile mode, and load dashboard', async ({ page }) => {
// Step 1: Open login page
await page.goto(`${FRONTEND_URL}/login`);
await expect(page).toHaveURL(/\/login/);
await expect(page.getByRole('heading', { name: /login/i })).toBeVisible();
// Step 2: Fill credentials and submit
await page.getByLabel(/email/i).fill(TEST_EMAIL);
await page.getByLabel(/password/i).fill(TEST_PASSWORD);
await page.getByRole('button', { name: /sign in|login/i }).click();
// Step 3: Wait for redirect to profile selection (since no UI mode selected)
await expect(page).toHaveURL(/\/profile-select/);
await expect(page.getByRole('heading', { name: /welcome to service finder/i })).toBeVisible();
// Step 4: Select Private Garage mode
await page.getByText(/private garage/i).click();
await expect(page.locator('.selected').filter({ hasText: /private garage/i })).toBeVisible();
// Step 5: Click Continue to Dashboard
await page.getByRole('button', { name: /continue to dashboard/i }).click();
// Step 6: Verify dashboard loads
await expect(page).toHaveURL(/\//);
await expect(page.getByRole('heading').filter({ hasText: /dashboard/i }).first()).toBeVisible();
// Step 7: Verify gamification trophies are present
await expect(page.getByText(/trophies|achievements/i).first()).toBeVisible();
// Step 8: Verify "Add Expense" link is present and clickable
const addExpenseLink = page.getByRole('link', { name: /add expense/i });
await expect(addExpenseLink).toBeVisible();
await addExpenseLink.click();
// Should navigate to add expense page
await expect(page.getByRole('heading', { name: /add expense/i })).toBeVisible();
});
test('should handle corporate fleet selection', async ({ page }) => {
await page.goto(`${FRONTEND_URL}/login`);
await page.getByLabel(/email/i).fill(TEST_EMAIL);
await page.getByLabel(/password/i).fill(TEST_PASSWORD);
await page.getByRole('button', { name: /sign in|login/i }).click();
await expect(page).toHaveURL(/\/profile-select/);
await page.getByText(/corporate fleet/i).click();
await page.getByRole('button', { name: /continue to dashboard/i }).click();
await expect(page).toHaveURL(/\//);
// Fleet dashboard may have different elements, but at least dashboard title
await expect(page.getByRole('heading').filter({ hasText: /dashboard/i }).first()).toBeVisible();
});
});

View File

@@ -0,0 +1,230 @@
import { test, expect } from '@playwright/test'
test.describe('Landing Page - Clean Garage & Bento HUD', () => {
test.beforeEach(async ({ page }) => {
// Navigate to the landing page and wait for network to be idle (background image loaded)
await page.goto('/')
await page.waitForLoadState('networkidle')
})
test('should display sticky header with CSS logo and button', async ({ page }) => {
// Check sticky header exists
const header = page.locator('header')
await expect(header).toBeVisible()
// Verify Compass + Search logo SVG icons are present
const compassIcon = header.locator('svg').first()
await expect(compassIcon).toBeVisible()
// Verify "SERVICEFINDER" text
await expect(header.locator('text=SERVICE')).toBeVisible()
await expect(header.locator('text=FINDER')).toBeVisible()
// Verify "Garázs Nyitása" button
const openGarageBtn = page.getByRole('button', { name: /Garázs Nyitása/i })
await expect(openGarageBtn).toBeVisible()
// Take screenshot of header
await header.screenshot({ path: 'test-results/screenshots/header-with-logo.png' })
})
test('should display 2-column hero layout with text and Bento cards', async ({ page }) => {
// Check main heading (Left column)
const heading = page.locator('h1')
await expect(heading).toContainText('Digitális Flotta')
await expect(heading).toContainText('Menedzsment')
// Check subheading
await expect(page.locator('text=Valós idejű költségkövetés')).toBeVisible()
// Check CTA button in left column
const ctaButton = page.getByRole('button', { name: /Garázs Nyitása/i }).first()
await expect(ctaButton).toBeVisible()
// Take full page screenshot showing 2-column layout
await page.screenshot({
path: 'test-results/screenshots/landing-two-column-layout.png',
fullPage: true
})
})
test('should display Bento-Grid with 5 HUD cards on the right', async ({ page }) => {
// Card 1: Statistics (Full width, top)
await expect(page.locator('text=Rendszerünkben kezelt járművek')).toBeVisible()
await expect(page.locator('text=1,245')).toBeVisible()
// Card 2: Fuel Cost (Middle left)
await expect(page.locator('text=Üzemanyag (E havi)')).toBeVisible()
await expect(page.locator('text=32.500')).toBeVisible()
// Card 3: Service Cost (Middle right)
await expect(page.locator('text=Várható Szerviz')).toBeVisible()
await expect(page.locator('text=48.000')).toBeVisible()
// Card 4: Security Badge (Bottom left)
await expect(page.locator('text=Security by Design')).toBeVisible()
await expect(page.locator('text=100% E2E titkosítás')).toBeVisible()
// Card 5: Fleet Radar (Bottom right)
await expect(page.locator('text=Flotta Radar')).toBeVisible()
await expect(page.locator('text=Aktív')).toBeVisible()
await expect(page.locator('text=Inaktív')).toBeVisible()
// Take screenshot of the Bento-Grid cards area
const bentoGrid = page.locator('.grid.grid-cols-2').last()
await bentoGrid.screenshot({ path: 'test-results/screenshots/bento-grid-cards.png' })
})
test('should have clean garage background with asymmetric overlay', async ({ page }) => {
// Check that the background image is loaded
const bgContainer = page.locator('div.fixed.inset-0').first()
await expect(bgContainer).toBeVisible()
// Verify background image URL contains 'garage_clean.png'
const bgStyle = await bgContainer.evaluate((el) =>
window.getComputedStyle(el).backgroundImage
)
expect(bgStyle).toContain('garage_clean.png')
// Take screenshot to verify background
await page.screenshot({
path: 'test-results/screenshots/clean-garage-background.png',
fullPage: true
})
})
test('should open login modal when clicking "Garázs Nyitása"', async ({ page }) => {
// Modal should not be visible initially
const modal = page.locator('text=Lépj be a garázsodba')
await expect(modal).not.toBeVisible()
// Click "Garázs Nyitása" button in header
const openGarageBtn = page.getByRole('button', { name: /Garázs Nyitása/i }).first()
await openGarageBtn.click()
// Wait for modal to appear
await expect(modal).toBeVisible()
// Verify modal content
await expect(page.locator('text=SERVICEFINDER')).toHaveCount(2) // Header + Modal
await expect(page.getByLabel(/Email cím/i)).toBeVisible()
await expect(page.getByLabel(/Jelszó/i)).toBeVisible()
// Take screenshot of open modal
await page.screenshot({
path: 'test-results/screenshots/login-modal-with-logo.png',
fullPage: false
})
})
test('should close modal when clicking backdrop', async ({ page }) => {
// Open modal
const openGarageBtn = page.getByRole('button', { name: /Garázs Nyitása/i }).first()
await openGarageBtn.click()
// Verify modal is open
const modal = page.locator('text=Lépj be a garázsodba')
await expect(modal).toBeVisible()
// Click backdrop (outside modal)
await page.locator('.fixed.inset-0.z-\\[100\\]').click({ position: { x: 10, y: 10 } })
// Modal should close
await expect(modal).not.toBeVisible()
})
test('should close modal when clicking X button', async ({ page }) => {
// Open modal
const openGarageBtn = page.getByRole('button', { name: /Garázs Nyitása/i }).first()
await openGarageBtn.click()
// Verify modal is open
const modal = page.locator('text=Lépj be a garázsodba')
await expect(modal).toBeVisible()
// Click close button (X)
const closeBtn = page.locator('button').filter({ has: page.locator('svg line[x1="18"][y1="6"]') })
await closeBtn.click()
// Modal should close
await expect(modal).not.toBeVisible()
})
test('should have proper card styling with glassmorphism', async ({ page }) => {
// Check one of the Bento cards for glassmorphism styles
const fuelCard = page.locator('text=Üzemanyag (E havi)').locator('..')
// Verify card is visible
await expect(fuelCard).toBeVisible()
// Check computed styles for backdrop-blur and transparency
const backdropFilter = await fuelCard.evaluate((el) =>
window.getComputedStyle(el).backdropFilter || window.getComputedStyle(el).webkitBackdropFilter
)
// Should have blur effect
expect(backdropFilter).toContain('blur')
// Take close-up screenshot of a card
await fuelCard.screenshot({ path: 'test-results/screenshots/card-glassmorphism-detail.png' })
})
test('should display all Lucide icons correctly', async ({ page }) => {
// Count SVG icons in the Bento cards
const svgIcons = page.locator('.grid.grid-cols-2 svg')
const iconCount = await svgIcons.count()
// Should have multiple icons (trending up, fuel, wrench, shield, car icons)
expect(iconCount).toBeGreaterThan(5)
// Verify specific icons are visible
await expect(page.locator('svg').filter({ has: page.locator('polyline[points*="22 7"]') })).toBeVisible() // TrendingUp
await expect(page.locator('svg').filter({ has: page.locator('path[d*="M14 22V4"]') })).toBeVisible() // Fuel
await expect(page.locator('svg').filter({ has: page.locator('path[d*="M12 22s8-4"]') })).toBeVisible() // Shield
})
test('should be responsive on mobile viewport', async ({ page }) => {
// Set mobile viewport
await page.setViewportSize({ width: 375, height: 667 })
// Wait for layout to adjust
await page.waitForTimeout(500)
// Header should still be visible
const header = page.locator('header')
await expect(header).toBeVisible()
// Main heading should be visible
await expect(page.locator('h1')).toBeVisible()
// Cards should stack vertically on mobile
await expect(page.locator('text=Rendszerünkben kezelt járművek')).toBeVisible()
// Take mobile screenshot
await page.screenshot({
path: 'test-results/screenshots/landing-mobile-view.png',
fullPage: true
})
})
test('should have proper color scheme (turquoise and dark blue)', async ({ page }) => {
// Check turquoise color (#65A5A0) is used
const turquoiseElements = page.locator('[class*="65A5A0"]')
const turquoiseCount = await turquoiseElements.count()
expect(turquoiseCount).toBeGreaterThan(0)
// Check dark blue color (#062535) is used
const darkBlueElements = page.locator('[class*="062535"]')
const darkBlueCount = await darkBlueElements.count()
expect(darkBlueCount).toBeGreaterThan(0)
// Verify button has turquoise background
const button = page.getByRole('button', { name: /Garázs Nyitása/i }).first()
const bgColor = await button.evaluate((el) =>
window.getComputedStyle(el).backgroundColor
)
// RGB equivalent of #65A5A0 is approximately rgb(101, 165, 160)
expect(bgColor).toMatch(/rgb\(101,\s*165,\s*160\)/)
})
})

View File

@@ -0,0 +1,217 @@
import { test, expect } from '@playwright/test'
test.describe('Neo-Glassmorphism Landing Page', () => {
test.beforeEach(async ({ page }) => {
// Navigate to the landing page
await page.goto('/')
})
test('should display sticky header with logo and button', async ({ page }) => {
// Check sticky header exists
const header = page.locator('header')
await expect(header).toBeVisible()
// Verify logo SVG icons are present
const compassIcon = header.locator('svg').first()
await expect(compassIcon).toBeVisible()
// Verify "Garázs Nyitása" button
const openGarageBtn = page.getByRole('button', { name: /Garázs Nyitása/i })
await expect(openGarageBtn).toBeVisible()
// Take screenshot of header
await header.screenshot({ path: 'test-results/screenshots/header-sticky.png' })
})
test('should display three asymmetric floating cards', async ({ page }) => {
// Wait for page to fully load
await page.waitForLoadState('networkidle')
// Card 1: HUD Costs (should contain "HUD Költségek" and "25.000 Ft")
const hudCard = page.locator('text=HUD Költségek').locator('..')
await expect(hudCard).toBeVisible()
await expect(page.locator('text=25.000 Ft')).toBeVisible()
// Card 2: Flotta Radar (should contain "Flotta Radar" and vehicle counts)
const fleetCard = page.locator('text=Flotta Radar').locator('..')
await expect(fleetCard).toBeVisible()
await expect(page.locator('text=Aktív')).toBeVisible()
// Card 3: Gamification (should contain "Gamifikáció" and "3450")
const gamificationCard = page.locator('text=Gamifikáció').locator('..')
await expect(gamificationCard).toBeVisible()
await expect(page.locator('text=3450')).toBeVisible()
await expect(page.locator('text=Usta Szerelő')).toBeVisible()
// Take full page screenshot showing all cards
await page.screenshot({
path: 'test-results/screenshots/landing-floating-cards.png',
fullPage: true
})
})
test('should display hero content with gradient background', async ({ page }) => {
// Check main heading
const heading = page.locator('h1')
await expect(heading).toContainText('Digitális Flotta')
await expect(heading).toContainText('Menedzsment')
// Check subheading
await expect(page.locator('text=Valós idejű költségkövetés')).toBeVisible()
// Check CTA button
const ctaButton = page.getByRole('button', { name: /Kezdjük el/i })
await expect(ctaButton).toBeVisible()
// Verify gradient background is applied (check computed styles)
const mainContainer = page.locator('div').first()
const bgColor = await mainContainer.evaluate((el) =>
window.getComputedStyle(el).backgroundImage
)
expect(bgColor).toContain('gradient')
})
test('should open login modal when clicking "Garázs Nyitása"', async ({ page }) => {
// Modal should not be visible initially
const modal = page.locator('text=Lépj be a garázsodba').locator('..')
await expect(modal).not.toBeVisible()
// Click "Garázs Nyitása" button
const openGarageBtn = page.getByRole('button', { name: /Garázs Nyitása/i })
await openGarageBtn.click()
// Wait for modal to appear
await expect(modal).toBeVisible()
// Verify modal content
await expect(page.locator('text=Lépj be a garázsodba')).toBeVisible()
await expect(page.getByLabel(/Email cím/i)).toBeVisible()
await expect(page.getByLabel(/Jelszó/i)).toBeVisible()
// Take screenshot of open modal
await page.screenshot({
path: 'test-results/screenshots/login-modal-open.png',
fullPage: false
})
})
test('should close modal when clicking backdrop', async ({ page }) => {
// Open modal
const openGarageBtn = page.getByRole('button', { name: /Garázs Nyitása/i })
await openGarageBtn.click()
// Wait for modal
const modal = page.locator('text=Lépj be a garázsodba').locator('..')
await expect(modal).toBeVisible()
// Click backdrop (outside modal)
const backdrop = page.locator('.fixed.inset-0').first()
await backdrop.click({ position: { x: 10, y: 10 } })
// Modal should close
await expect(modal).not.toBeVisible()
})
test('should close modal when clicking X button', async ({ page }) => {
// Open modal
const openGarageBtn = page.getByRole('button', { name: /Garázs Nyitása/i })
await openGarageBtn.click()
// Wait for modal
const modal = page.locator('text=Lépj be a garázsodba').locator('..')
await expect(modal).toBeVisible()
// Click close button (X icon)
const closeBtn = page.locator('button').filter({ has: page.locator('svg line[x1="18"]') }).first()
await closeBtn.click()
// Modal should close
await expect(modal).not.toBeVisible()
})
test('should open modal when clicking hero CTA button', async ({ page }) => {
// Click "Kezdjük el" button
const ctaButton = page.getByRole('button', { name: /Kezdjük el/i })
await ctaButton.click()
// Modal should open
const modal = page.locator('text=Lépj be a garázsodba').locator('..')
await expect(modal).toBeVisible()
})
test('should have proper glassmorphism effects on cards', async ({ page }) => {
await page.waitForLoadState('networkidle')
// Check HUD card has backdrop-blur
const hudCard = page.locator('text=HUD Költségek').locator('..')
const backdropFilter = await hudCard.evaluate((el) =>
window.getComputedStyle(el).backdropFilter || window.getComputedStyle(el).webkitBackdropFilter
)
expect(backdropFilter).toContain('blur')
// Check card has border with turquoise color
const borderColor = await hudCard.evaluate((el) =>
window.getComputedStyle(el).borderColor
)
// Border should exist (not 'none')
expect(borderColor).not.toBe('none')
})
test('should display CSS progress ring in gamification card', async ({ page }) => {
await page.waitForLoadState('networkidle')
// Find the SVG circle elements in the progress ring
const progressRing = page.locator('svg circle[stroke="#65A5A0"]')
await expect(progressRing).toBeVisible()
// Verify trophy icons are present
const trophies = page.locator('svg').filter({ hasText: '' }).locator('path[d*="M6 9H4.5"]')
const trophyCount = await trophies.count()
expect(trophyCount).toBeGreaterThanOrEqual(3)
})
test('should have responsive layout on mobile', async ({ page }) => {
// Set mobile viewport
await page.setViewportSize({ width: 375, height: 667 })
// Check header is still visible
const header = page.locator('header')
await expect(header).toBeVisible()
// Check cards are still visible (may stack differently)
await expect(page.locator('text=HUD Költségek')).toBeVisible()
await expect(page.locator('text=Flotta Radar')).toBeVisible()
await expect(page.locator('text=Gamifikáció')).toBeVisible()
// Take mobile screenshot
await page.screenshot({
path: 'test-results/screenshots/landing-mobile.png',
fullPage: true
})
})
test('visual regression: full landing page', async ({ page }) => {
await page.waitForLoadState('networkidle')
// Take full page screenshot for visual comparison
await page.screenshot({
path: 'test-results/screenshots/landing-full-page.png',
fullPage: true
})
})
test('visual regression: modal state', async ({ page }) => {
// Open modal
const openGarageBtn = page.getByRole('button', { name: /Garázs Nyitása/i })
await openGarageBtn.click()
// Wait for animation
await page.waitForTimeout(500)
// Take screenshot
await page.screenshot({
path: 'test-results/screenshots/modal-full-state.png',
fullPage: false
})
})
})

View File

@@ -0,0 +1,35 @@
import { test, expect, chromium } from '@playwright/test';
test('Phase 1 - Landing page visual capture', async () => {
// Connect to the remote Chrome instance on faktor01 via CDP
const browser = await chromium.connectOverCDP('http://100.93.27.29:3030');
const context = await browser.newContext({
viewport: { width: 1440, height: 900 },
});
const page = await context.newPage();
// Load the production/staging frontend
await page.goto('https://app.servicefinder.hu', { timeout: 30000 });
// Wait for full page load including images
await page.waitForLoadState('networkidle');
// Small extra wait for the background image to render
await page.waitForTimeout(2000);
// Take a full-page screenshot
await page.screenshot({
path: 'test-results/landing-phase1.png',
fullPage: true,
});
// Basic sanity: page should have content
const bodyText = await page.textContent('body');
expect(bodyText).toContain('SERVICE');
expect(bodyText).toContain('FINDER');
console.log('✅ Landing page screenshot saved as test-results/landing-phase1.png');
await browser.close();
});

View File

@@ -0,0 +1,24 @@
import { test, expect } from '@playwright/test'
test.describe('Logo Screenshot', () => {
test('capture custom SVG logo', async ({ page }) => {
// Navigate to the landing page
await page.goto('/')
// Wait for page to load
await page.waitForLoadState('networkidle')
// Find the header
const header = page.locator('header')
await expect(header).toBeVisible()
// Take screenshot of the entire header
await header.screenshot({ path: 'frontend/test-results/screenshots/custom-logo-header.png' })
// Take a close-up of just the logo area
const logoArea = header.locator('div').first()
await logoArea.screenshot({ path: 'frontend/test-results/screenshots/custom-logo-closeup.png' })
console.log('✅ Screenshots saved to frontend/test-results/screenshots/')
})
})

View File

@@ -0,0 +1,25 @@
import { test, expect, chromium } from '@playwright/test';
test('Távoli böngésző kapcsolat és internet elérés tesztje', async () => {
// Connect to the remote Chrome instance via CDP (Chrome DevTools Protocol)
const browser = await chromium.connectOverCDP('http://100.93.27.29:3030');
const context = await browser.newContext();
const page = await context.newPage();
// Megkíséreljük betölteni az éles/staging oldalt a külső szerverről
await page.goto('https://app.servicefinder.hu', { timeout: 30000 });
// Várunk egy kicsit, hogy biztosan betöltsön
await page.waitForLoadState('networkidle');
// Készítünk egy képernyőfotót a bizonyításhoz
await page.screenshot({ path: 'test-results/remote-sanity-proof.png', fullPage: true });
// Alapvető ellenőrzés
const title = await page.title();
console.log('A távoli böngésző ezt az oldalcímet látja: ', title);
expect(title).not.toBeNull();
await browser.close();
});