Initial commit - production deployment
This commit is contained in:
212
frontend/tests/operations/add-product.spec.ts
Normal file
212
frontend/tests/operations/add-product.spec.ts
Normal file
@@ -0,0 +1,212 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { generateTestId, acceptCookieConsent } from '../helpers/utils';
|
||||
|
||||
test.describe('Add New Product/Recipe', () => {
|
||||
// Use authenticated state
|
||||
test.use({ storageState: 'tests/.auth/user.json' });
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// Accept cookie consent if present
|
||||
await acceptCookieConsent(page);
|
||||
});
|
||||
|
||||
test('should open Add wizard from dashboard', async ({ page }) => {
|
||||
await page.goto('/app/dashboard');
|
||||
await acceptCookieConsent(page);
|
||||
|
||||
// Click unified Add button
|
||||
const addButton = page.getByRole('button', { name: /^add$|^añadir$|^\+$/i }).first();
|
||||
|
||||
if (await addButton.isVisible().catch(() => false)) {
|
||||
await addButton.click();
|
||||
|
||||
// Wait for wizard/modal to open
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Should show options (Recipe, Order, Production, etc.)
|
||||
await expect(page.locator('body')).toContainText(/recipe|receta|product|producto/i);
|
||||
}
|
||||
});
|
||||
|
||||
test('should successfully add a new product', async ({ page }) => {
|
||||
await page.goto('/app/operations/recipes');
|
||||
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Look for Add/Create button
|
||||
const addButton = page.getByRole('button', { name: /add|create|new|añadir|crear|nuevo/i }).first();
|
||||
|
||||
if (await addButton.isVisible().catch(() => false)) {
|
||||
await addButton.click();
|
||||
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Fill in product details
|
||||
const productName = `Test Product ${generateTestId()}`;
|
||||
|
||||
const nameInput = page.getByLabel(/product.*name|name|nombre.*producto|nombre/i);
|
||||
|
||||
if (await nameInput.isVisible().catch(() => false)) {
|
||||
await nameInput.fill(productName);
|
||||
|
||||
// Fill in price
|
||||
const priceInput = page.getByLabel(/price|precio|cost|costo/i);
|
||||
|
||||
if (await priceInput.isVisible().catch(() => false)) {
|
||||
await priceInput.fill('9.99');
|
||||
}
|
||||
|
||||
// Select category if available
|
||||
const categorySelect = page.getByLabel(/category|categoría|type|tipo/i);
|
||||
|
||||
if (await categorySelect.isVisible().catch(() => false)) {
|
||||
await categorySelect.click();
|
||||
|
||||
// Select first option
|
||||
const firstOption = page.getByRole('option').first();
|
||||
|
||||
if (await firstOption.isVisible({ timeout: 2000 }).catch(() => false)) {
|
||||
await firstOption.click();
|
||||
}
|
||||
}
|
||||
|
||||
// Submit form
|
||||
const submitButton = page.getByRole('button', { name: /save|create|submit|guardar|crear|enviar/i });
|
||||
await submitButton.click();
|
||||
|
||||
// Should show success message
|
||||
await expect(page.locator('body')).toContainText(/success|created|éxito|creado/i, {
|
||||
timeout: 5000,
|
||||
});
|
||||
|
||||
// Product should appear in list
|
||||
await expect(page.locator('body')).toContainText(productName, { timeout: 5000 });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('should show validation errors for missing required fields', async ({ page }) => {
|
||||
await page.goto('/app/operations/recipes');
|
||||
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Look for Add button
|
||||
const addButton = page.getByRole('button', { name: /add|create|new|añadir|crear|nuevo/i }).first();
|
||||
|
||||
if (await addButton.isVisible().catch(() => false)) {
|
||||
await addButton.click();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Try to submit without filling fields
|
||||
const submitButton = page.getByRole('button', { name: /save|create|submit|guardar|crear|enviar/i });
|
||||
|
||||
if (await submitButton.isVisible().catch(() => false)) {
|
||||
await submitButton.click();
|
||||
|
||||
// Should show validation errors
|
||||
await expect(page.locator('body')).toContainText(/required|obligatorio|necesario/i, {
|
||||
timeout: 3000,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('should add ingredients to a recipe', async ({ page }) => {
|
||||
await page.goto('/app/operations/recipes');
|
||||
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const addButton = page.getByRole('button', { name: /add|create|new|añadir|crear|nuevo/i }).first();
|
||||
|
||||
if (await addButton.isVisible().catch(() => false)) {
|
||||
await addButton.click();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Fill basic info
|
||||
const nameInput = page.getByLabel(/product.*name|name|nombre.*producto|nombre/i);
|
||||
|
||||
if (await nameInput.isVisible().catch(() => false)) {
|
||||
await nameInput.fill(`Test Recipe ${generateTestId()}`);
|
||||
|
||||
// Look for "Add Ingredient" button
|
||||
const addIngredientButton = page.getByRole('button', { name: /add.*ingredient|añadir.*ingrediente/i });
|
||||
|
||||
if (await addIngredientButton.isVisible().catch(() => false)) {
|
||||
await addIngredientButton.click();
|
||||
|
||||
// Fill ingredient details
|
||||
const ingredientInput = page.getByLabel(/ingredient|ingrediente/i).first();
|
||||
|
||||
if (await ingredientInput.isVisible().catch(() => false)) {
|
||||
await ingredientInput.fill('Flour');
|
||||
|
||||
// Fill quantity
|
||||
const quantityInput = page.getByLabel(/quantity|cantidad/i).first();
|
||||
|
||||
if (await quantityInput.isVisible().catch(() => false)) {
|
||||
await quantityInput.fill('500');
|
||||
}
|
||||
|
||||
// Ingredient should be added
|
||||
await expect(page.locator('body')).toContainText(/flour|harina/i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('should upload product image', async ({ page }) => {
|
||||
await page.goto('/app/operations/recipes');
|
||||
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const addButton = page.getByRole('button', { name: /add|create|new|añadir|crear|nuevo/i }).first();
|
||||
|
||||
if (await addButton.isVisible().catch(() => false)) {
|
||||
await addButton.click();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Look for file upload
|
||||
const fileInput = page.locator('input[type="file"]');
|
||||
|
||||
if (await fileInput.isVisible().catch(() => false)) {
|
||||
// File upload is available
|
||||
await expect(fileInput).toBeAttached();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('should cancel product creation', async ({ page }) => {
|
||||
await page.goto('/app/operations/recipes');
|
||||
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const addButton = page.getByRole('button', { name: /add|create|new|añadir|crear|nuevo/i }).first();
|
||||
|
||||
if (await addButton.isVisible().catch(() => false)) {
|
||||
await addButton.click();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Fill some data
|
||||
const nameInput = page.getByLabel(/product.*name|name|nombre.*producto|nombre/i);
|
||||
|
||||
if (await nameInput.isVisible().catch(() => false)) {
|
||||
await nameInput.fill('Test Product to Cancel');
|
||||
|
||||
// Look for Cancel button
|
||||
const cancelButton = page.getByRole('button', { name: /cancel|cancelar|close|cerrar/i });
|
||||
|
||||
if (await cancelButton.isVisible().catch(() => false)) {
|
||||
await cancelButton.click();
|
||||
|
||||
// Should close form/modal
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Should not show the test product
|
||||
const bodyText = await page.locator('body').textContent();
|
||||
expect(bodyText).not.toContain('Test Product to Cancel');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user