Files
roa2web-service-auto/reports-app/frontend/tests/e2e/invoices/invoices.spec.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

214 lines
7.3 KiB
JavaScript

import { test, expect } from '@playwright/test';
import { LoginPage } from '../../page-objects/LoginPage.js';
import { InvoicesPage } from '../../page-objects/InvoicesPage.js';
import { testCredentials } from '../../fixtures/auth.js';
import { mockInvoices } from '../../fixtures/invoices.js';
test.describe('Invoices View', () => {
let loginPage;
let invoicesPage;
test.beforeEach(async ({ page }) => {
loginPage = new LoginPage(page);
invoicesPage = new InvoicesPage(page);
// Mock authentication
await page.route('**/api/auth/login', async route => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
access_token: 'mock_access_token',
refresh_token: 'mock_refresh_token',
user: { id: 1, username: 'testuser', full_name: 'Test User' }
}),
});
});
// Mock companies
await page.route('**/api/companies', async route => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify([
{ code: 'COMP1', name: 'Compania Test 1' }
]),
});
});
// Mock invoices endpoint
await page.route('**/api/invoices/COMP1', async route => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(mockInvoices),
});
});
// Login and navigate to invoices
await loginPage.navigate();
await loginPage.login(testCredentials.valid.username, testCredentials.valid.password);
await page.waitForURL('/dashboard');
await invoicesPage.navigate();
});
test('should display invoices page correctly', async ({ page: _page }) => {
expect(await invoicesPage.isOnInvoicesPage()).toBe(true);
const title = await invoicesPage.getPageTitle();
expect(title).toContain('Facturi');
});
test('should show company selection when no company selected', async ({ page: _page }) => {
await invoicesPage.waitForPageLoad();
expect(await invoicesPage.isCompanySelectionVisible()).toBe(true);
expect(await invoicesPage.isInvoicesTableVisible()).toBe(false);
});
test('should display invoices table after company selection', async ({ page }) => {
await invoicesPage.waitForPageLoad();
await invoicesPage.selectCompany('Compania Test 1');
await page.waitForSelector(invoicesPage.invoicesTable, { timeout: 10000 });
expect(await invoicesPage.isInvoicesTableVisible()).toBe(true);
});
test('should filter invoices by search term', async ({ page }) => {
await invoicesPage.waitForPageLoad();
await invoicesPage.selectCompany('Compania Test 1');
await page.waitForSelector(invoicesPage.invoicesTable);
// Search for specific invoice
await invoicesPage.searchInvoices('INV001');
await invoicesPage.waitForLoadingToFinish();
const visibleRows = await invoicesPage.getVisibleInvoicesCount();
expect(visibleRows).toBeGreaterThan(0);
// Check that displayed invoices contain search term
const firstRowData = await invoicesPage.getFirstInvoiceData();
expect(firstRowData.number).toContain('INV001');
});
test('should filter invoices by status', async ({ page }) => {
await invoicesPage.waitForPageLoad();
await invoicesPage.selectCompany('Compania Test 1');
await page.waitForSelector(invoicesPage.invoicesTable);
// Filter by paid status
await invoicesPage.filterByStatus('paid');
await invoicesPage.waitForLoadingToFinish();
const visibleRows = await invoicesPage.getVisibleInvoicesCount();
expect(visibleRows).toBeGreaterThan(0);
});
test('should sort invoices by date', async ({ page }) => {
await invoicesPage.waitForPageLoad();
await invoicesPage.selectCompany('Compania Test 1');
await page.waitForSelector(invoicesPage.invoicesTable);
// Click date column header to sort
await invoicesPage.sortByColumn('date');
await invoicesPage.waitForLoadingToFinish();
// Verify sorting worked
const firstRowDate = await invoicesPage.getFirstInvoiceData();
expect(firstRowDate.date).toBeTruthy();
});
test('should display invoice details when clicking on row', async ({ page }) => {
await invoicesPage.waitForPageLoad();
await invoicesPage.selectCompany('Compania Test 1');
await page.waitForSelector(invoicesPage.invoicesTable);
// Click on first invoice row
await invoicesPage.clickFirstInvoiceRow();
// Check if details panel or modal appears
expect(await invoicesPage.isInvoiceDetailsVisible()).toBe(true);
});
test('should export invoices data', async ({ page }) => {
await invoicesPage.waitForPageLoad();
await invoicesPage.selectCompany('Compania Test 1');
await page.waitForSelector(invoicesPage.invoicesTable);
// Set up download handler
const downloadPromise = page.waitForEvent('download');
await invoicesPage.clickExportButton();
const download = await downloadPromise;
expect(download.suggestedFilename()).toContain('facturi');
});
test('should handle pagination correctly', async ({ page }) => {
// Mock large dataset
await page.route('**/api/invoices/COMP1*', async route => {
const url = route.request().url();
const urlParams = new URL(url).searchParams;
const page_num = parseInt(urlParams.get('page') || '1');
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
items: mockInvoices.slice((page_num - 1) * 10, page_num * 10),
total: 25,
page: page_num,
size: 10,
pages: 3
}),
});
});
await invoicesPage.waitForPageLoad();
await invoicesPage.selectCompany('Compania Test 1');
await page.waitForSelector(invoicesPage.invoicesTable);
// Check pagination controls appear
expect(await invoicesPage.isPaginationVisible()).toBe(true);
// Navigate to next page
await invoicesPage.goToNextPage();
await invoicesPage.waitForLoadingToFinish();
// Verify page changed
const currentPage = await invoicesPage.getCurrentPage();
expect(currentPage).toBe(2);
});
test('should handle API errors gracefully', async ({ page }) => {
// Mock API error
await page.route('**/api/invoices/COMP1', async route => {
await route.fulfill({
status: 500,
contentType: 'application/json',
body: JSON.stringify({ detail: 'Internal server error' }),
});
});
await invoicesPage.waitForPageLoad();
await invoicesPage.selectCompany('Compania Test 1');
// Should show error message
const errorToast = page.locator('.p-toast-message-error');
if (await errorToast.isVisible()) {
const errorText = await errorToast.textContent();
expect(errorText.toLowerCase()).toContain('eroare');
}
});
test('should refresh data when refresh button clicked', async ({ page }) => {
await invoicesPage.waitForPageLoad();
await invoicesPage.selectCompany('Compania Test 1');
await page.waitForSelector(invoicesPage.invoicesTable);
// Click refresh button
await invoicesPage.clickRefreshButton();
await invoicesPage.waitForLoadingToFinish();
// Table should still be visible after refresh
expect(await invoicesPage.isInvoicesTableVisible()).toBe(true);
});
});