feat: Goa GEL Blockchain e-Licensing Platform - Full Stack Implementation
Complete implementation of the Goa Government e-Licensing platform with: Backend: - NestJS API with JWT authentication - PostgreSQL database with Knex ORM - Redis caching and session management - MinIO document storage - Hyperledger Besu blockchain integration - Multi-department workflow system - Comprehensive API tests (266/282 passing) Frontend: - Angular 21 with standalone components - Angular Material + TailwindCSS UI - Visual workflow builder - Document upload with progress tracking - Blockchain explorer integration - Role-based dashboards (Admin, Department, Citizen) - E2E tests with Playwright (37 tests) Infrastructure: - Docker Compose orchestration - Blockscout blockchain explorer - Development and production configurations
This commit is contained in:
163
frontend/e2e/auth.spec.ts
Normal file
163
frontend/e2e/auth.spec.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('Authentication', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test.describe('Login Page', () => {
|
||||
test('should display login page with email and password fields', async ({ page }) => {
|
||||
await page.goto('/auth/login');
|
||||
|
||||
await expect(page.getByText('Goa GEL Platform')).toBeVisible();
|
||||
await expect(page.getByLabel('Email')).toBeVisible();
|
||||
await expect(page.getByLabel('Password')).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: 'Sign In' })).toBeVisible();
|
||||
});
|
||||
|
||||
test('should display demo accounts section', async ({ page }) => {
|
||||
await page.goto('/auth/login');
|
||||
|
||||
await expect(page.getByRole('heading', { name: 'Demo Accounts' })).toBeVisible();
|
||||
await expect(page.getByText('Admin').first()).toBeVisible();
|
||||
await expect(page.getByText('Fire Department').first()).toBeVisible();
|
||||
await expect(page.getByText('Citizen').first()).toBeVisible();
|
||||
});
|
||||
|
||||
test('should auto-fill credentials when clicking demo account', async ({ page }) => {
|
||||
await page.goto('/auth/login');
|
||||
|
||||
// Click on the Admin demo card
|
||||
await page.click('text=Admin');
|
||||
|
||||
const emailInput = page.getByLabel('Email');
|
||||
const passwordInput = page.getByLabel('Password');
|
||||
|
||||
await expect(emailInput).toHaveValue('admin@goa.gov.in');
|
||||
await expect(passwordInput).toHaveValue('Admin@123');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Login Flow - Admin', () => {
|
||||
test('should login as admin and redirect to admin dashboard', async ({ page }) => {
|
||||
await page.goto('/auth/login');
|
||||
|
||||
// Fill credentials
|
||||
await page.getByLabel('Email').fill('admin@goa.gov.in');
|
||||
await page.getByLabel('Password').fill('Admin@123');
|
||||
|
||||
// Submit
|
||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
||||
|
||||
// Wait for navigation and verify redirect
|
||||
await page.waitForURL('**/admin**', { timeout: 10000 });
|
||||
|
||||
// Verify admin dashboard is shown
|
||||
await expect(page).toHaveURL(/.*admin.*/);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Login Flow - Citizen', () => {
|
||||
test('should login as citizen and redirect to dashboard', async ({ page }) => {
|
||||
await page.goto('/auth/login');
|
||||
|
||||
// Fill credentials
|
||||
await page.getByLabel('Email').fill('citizen@example.com');
|
||||
await page.getByLabel('Password').fill('Citizen@123');
|
||||
|
||||
// Submit
|
||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
||||
|
||||
// Wait for navigation
|
||||
await page.waitForURL('**/dashboard**', { timeout: 10000 });
|
||||
|
||||
await expect(page).toHaveURL(/.*dashboard.*/);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Login Flow - Department', () => {
|
||||
test('should login as fire department and redirect to dashboard', async ({ page }) => {
|
||||
await page.goto('/auth/login');
|
||||
|
||||
// Fill credentials
|
||||
await page.getByLabel('Email').fill('fire@goa.gov.in');
|
||||
await page.getByLabel('Password').fill('Fire@123');
|
||||
|
||||
// Submit
|
||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
||||
|
||||
// Wait for navigation
|
||||
await page.waitForURL('**/dashboard**', { timeout: 10000 });
|
||||
|
||||
await expect(page).toHaveURL(/.*dashboard.*/);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Login Validation', () => {
|
||||
test('should show error for invalid credentials', async ({ page }) => {
|
||||
await page.goto('/auth/login');
|
||||
|
||||
// Fill invalid credentials
|
||||
await page.getByLabel('Email').fill('invalid@email.com');
|
||||
await page.getByLabel('Password').fill('wrongpassword');
|
||||
|
||||
// Submit
|
||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
||||
|
||||
// Wait for error message
|
||||
await expect(page.getByText(/invalid|error/i)).toBeVisible({ timeout: 10000 });
|
||||
});
|
||||
|
||||
test('should disable submit button when form is invalid', async ({ page }) => {
|
||||
await page.goto('/auth/login');
|
||||
|
||||
const submitButton = page.getByRole('button', { name: 'Sign In' });
|
||||
|
||||
// Initially disabled (empty fields)
|
||||
await expect(submitButton).toBeDisabled();
|
||||
|
||||
// Fill only email
|
||||
await page.getByLabel('Email').fill('test@email.com');
|
||||
await expect(submitButton).toBeDisabled();
|
||||
|
||||
// Fill password
|
||||
await page.getByLabel('Password').fill('password');
|
||||
await expect(submitButton).toBeEnabled();
|
||||
});
|
||||
|
||||
test('should show validation error for invalid email format', async ({ page }) => {
|
||||
await page.goto('/auth/login');
|
||||
|
||||
// Fill invalid email
|
||||
const emailInput = page.getByLabel('Email');
|
||||
await emailInput.fill('notanemail');
|
||||
await emailInput.blur();
|
||||
|
||||
await expect(page.getByText('Please enter a valid email')).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Password Toggle', () => {
|
||||
test('should toggle password visibility', async ({ page }) => {
|
||||
await page.goto('/auth/login');
|
||||
|
||||
const passwordInput = page.getByLabel('Password');
|
||||
await passwordInput.fill('testpassword');
|
||||
|
||||
// Initially password is hidden
|
||||
await expect(passwordInput).toHaveAttribute('type', 'password');
|
||||
|
||||
// Click visibility toggle button
|
||||
await page.locator('button:has(mat-icon:has-text("visibility_off"))').click();
|
||||
|
||||
// Password should be visible
|
||||
await expect(passwordInput).toHaveAttribute('type', 'text');
|
||||
|
||||
// Click again to hide
|
||||
await page.locator('button:has(mat-icon:has-text("visibility"))').click();
|
||||
|
||||
// Password should be hidden again
|
||||
await expect(passwordInput).toHaveAttribute('type', 'password');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user