Files
roa2web-service-auto/reports-app/frontend/tests/page-objects/LoginPage.js
Marius Mutu 6b13ffa183 Initial commit: ROA2WEB - FastAPI + Vue.js + Telegram Bot
Modern ERP Reports Application with microservices architecture

Tech Stack:
- Backend: FastAPI + python-oracledb (Oracle DB integration)
- Frontend: Vue.js 3 + PrimeVue + Vite
- Telegram Bot: python-telegram-bot + SQLite
- Infrastructure: Shared database pool, JWT authentication, SSH tunnel

Features:
- FastAPI backend with async Oracle connection pool
- Vue.js 3 responsive frontend with PrimeVue components
- Telegram bot alternative interface
- Microservices architecture with shared components
- Complete deployment support (Linux Docker + Windows IIS)
- Comprehensive testing (Playwright E2E + pytest)

Repository Structure:
- reports-app/ - Main application (backend, frontend, telegram-bot)
- shared/ - Shared components (database pool, auth, utils)
- deployment/ - Deployment scripts (Linux & Windows)
- docs/ - Project documentation
- security/ - Security scanning and git hooks
2025-10-25 14:55:08 +03:00

99 lines
2.7 KiB
JavaScript

import { BasePage } from './BasePage.js';
export class LoginPage extends BasePage {
constructor(page) {
super(page);
// Selectors
this.usernameInput = '#username';
this.passwordInput = '#password input';
this.loginButton = 'button[type="submit"]';
this.errorMessage = '.error-message';
this.loadingSpinner = '.p-button-loading';
this.loginTitle = '.login-title';
this.loginCard = '.login-card';
// Form validation selectors
this.usernameError = '.field:has(#username) .p-error';
this.passwordError = '.field:has(#password) .p-error';
this.invalidField = '.p-invalid';
}
async navigate() {
await this.page.goto('/');
await this.page.waitForSelector(this.loginCard);
}
async fillCredentials(username, password) {
await this.page.fill(this.usernameInput, username);
await this.page.fill(this.passwordInput, password);
}
async clickLogin() {
await this.page.click(this.loginButton);
}
async login(username, password) {
await this.fillCredentials(username, password);
await this.clickLogin();
}
async waitForLoginResult() {
// Wait for either redirect to dashboard or error message
try {
await Promise.race([
this.page.waitForURL('/dashboard', { timeout: 5000 }),
this.page.waitForSelector(this.errorMessage, { timeout: 5000 })
]);
} catch (error) {
// Continue - we'll check the state separately
}
}
async isOnLoginPage() {
return await this.page.locator(this.loginTitle).isVisible();
}
async isLoginButtonDisabled() {
return await this.page.locator(this.loginButton).isDisabled();
}
async isLoading() {
return await this.page.locator(this.loadingSpinner).isVisible();
}
async getErrorMessage() {
const errorElement = this.page.locator(this.errorMessage);
if (await errorElement.isVisible()) {
return await errorElement.textContent();
}
return null;
}
async getFieldError(field) {
const selector = field === 'username' ? this.usernameError : this.passwordError;
const errorElement = this.page.locator(selector);
if (await errorElement.isVisible()) {
return await errorElement.textContent();
}
return null;
}
async hasInvalidField() {
return await this.page.locator(this.invalidField).count() > 0;
}
async clearForm() {
await this.page.fill(this.usernameInput, '');
await this.page.fill(this.passwordInput, '');
}
async validateFormFields() {
// Trigger validation by clicking outside fields
await this.page.click(this.loginCard);
}
async getPageTitle() {
return await this.page.locator(this.loginTitle).textContent();
}
}