Initial commit
This commit is contained in:
@@ -0,0 +1,261 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('Admin - Atribuição de Provas (Assignments)', () => {
|
||||
// TODO: Fazer login como admin
|
||||
// test.beforeEach(async ({ page }) => {
|
||||
// await page.goto('/auth/login');
|
||||
// await page.getByLabel(/email/i).fill('[email protected]');
|
||||
// await page.getByLabel(/senha/i).fill('123456');
|
||||
// await page.getByRole('button', { name: /entrar/i }).click();
|
||||
// await page.waitForURL(/\/dispatcher/);
|
||||
// await page.getByRole('button', { name: /admin/i }).click();
|
||||
// });
|
||||
|
||||
test.describe('Lista de Atribuições', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/assignments');
|
||||
});
|
||||
|
||||
test('deve mostrar lista de atribuições', async ({ page }) => {
|
||||
await expect(page.getByText(/atribuições|assignments/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve ter botão de criar atribuição', async ({ page }) => {
|
||||
await expect(page.getByRole('button', { name: /nova|criar/i })).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve mostrar turma, template e datas', async ({ page }) => {
|
||||
const assignmentRow = page.locator('tr').nth(1);
|
||||
if (await assignmentRow.isVisible()) {
|
||||
await expect(assignmentRow.getByText(/\d{4}-\d{2}-\d{2}/)).toBeVisible(); // Data
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Criar Nova Atribuição', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/assignments/add');
|
||||
});
|
||||
|
||||
test('deve mostrar formulário de criação', async ({ page }) => {
|
||||
await expect(page.getByRole('combobox', { name: /turma|class/i })).toBeVisible();
|
||||
await expect(page.getByRole('combobox', { name: /template/i })).toBeVisible();
|
||||
await expect(page.getByLabel(/data início|start date/i)).toBeVisible();
|
||||
await expect(page.getByLabel(/data fim|end date/i)).toBeVisible();
|
||||
await expect(page.getByLabel(/tempo limite|time limit/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve listar turmas disponíveis', async ({ page }) => {
|
||||
const classSelect = page.getByRole('combobox', { name: /turma|class/i });
|
||||
const options = await classSelect.locator('option').count();
|
||||
|
||||
expect(options).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('deve listar templates disponíveis', async ({ page }) => {
|
||||
const templateSelect = page.getByRole('combobox', { name: /template/i });
|
||||
const options = await templateSelect.locator('option').count();
|
||||
|
||||
// Pode ser 0 se não houver templates
|
||||
expect(options).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
|
||||
test('deve criar atribuição com dados válidos', async ({ page }) => {
|
||||
const timestamp = Date.now();
|
||||
|
||||
// Selecionar turma
|
||||
const classSelect = page.getByRole('combobox', { name: /turma|class/i });
|
||||
if ((await classSelect.locator('option').count()) > 0) {
|
||||
await classSelect.selectOption({ index: 0 });
|
||||
}
|
||||
|
||||
// Selecionar template
|
||||
const templateSelect = page.getByRole('combobox', { name: /template/i });
|
||||
if ((await templateSelect.locator('option').count()) > 0) {
|
||||
await templateSelect.selectOption({ index: 0 });
|
||||
}
|
||||
|
||||
// Datas
|
||||
await page.getByLabel(/data início|start date/i).fill('2025-02-01');
|
||||
await page.getByLabel(/data fim|end date/i).fill('2025-02-28');
|
||||
|
||||
// Tempo limite (em minutos)
|
||||
await page.getByLabel(/tempo limite|time limit/i).fill('60');
|
||||
|
||||
await page.getByRole('button', { name: /criar|salvar/i }).click();
|
||||
|
||||
await expect(page).toHaveURL(/\/admin\/dashboard\/assignments/, { timeout: 10000 });
|
||||
});
|
||||
|
||||
test('deve validar data fim posterior a data início', async ({ page }) => {
|
||||
await page.getByLabel(/data início|start date/i).fill('2025-02-15');
|
||||
await page.getByLabel(/data fim|end date/i).fill('2025-02-01');
|
||||
|
||||
await page.getByRole('button', { name: /criar|salvar/i }).click();
|
||||
|
||||
await expect(page.getByText(/fim.*posterior|data inválida/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve validar campos obrigatórios', async ({ page }) => {
|
||||
await page.getByRole('button', { name: /criar|salvar/i }).click();
|
||||
|
||||
await expect(page.getByText(/obrigatório|required/i)).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Atribuição por Turma', () => {
|
||||
test('deve pré-selecionar turma se vier da página da turma', async ({ page }) => {
|
||||
// TODO: Testar vindo da página de detalhes da turma
|
||||
// await page.goto('/admin/dashboard/class/edit/class-id');
|
||||
// await page.getByRole('button', { name: /atribuir prova/i }).click();
|
||||
|
||||
// const classSelect = page.getByRole('combobox', { name: /turma/i });
|
||||
// const value = await classSelect.inputValue();
|
||||
// expect(value).toBe('class-id');
|
||||
});
|
||||
|
||||
test('deve mostrar informações da turma', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/assignments/add');
|
||||
|
||||
// Após selecionar turma, pode mostrar info
|
||||
const classSelect = page.getByRole('combobox', { name: /turma/i });
|
||||
if ((await classSelect.locator('option').count()) > 0) {
|
||||
await classSelect.selectOption({ index: 0 });
|
||||
|
||||
// Pode mostrar número de alunos
|
||||
// await expect(page.getByText(/\d+ alunos/i)).toBeVisible();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Editar Atribuição', () => {
|
||||
test('deve carregar dados da atribuição', async ({ page }) => {
|
||||
// TODO: Editar atribuição existente
|
||||
await page.goto('/admin/dashboard/assignments/edit/assignment-id');
|
||||
|
||||
await expect(page.getByRole('combobox', { name: /turma/i })).not.toBeEmpty();
|
||||
await expect(page.getByRole('combobox', { name: /template/i })).not.toBeEmpty();
|
||||
});
|
||||
|
||||
test('deve permitir modificar datas e tempo', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/assignments/edit/assignment-id');
|
||||
|
||||
await page.getByLabel(/data início|start date/i).fill('2025-03-01');
|
||||
await page.getByLabel(/data fim|end date/i).fill('2025-03-31');
|
||||
await page.getByLabel(/tempo limite|time limit/i).fill('90');
|
||||
|
||||
await page.getByRole('button', { name: /salvar|atualizar/i }).click();
|
||||
|
||||
await expect(page).toHaveURL(/\/admin\/dashboard\/assignments/, { timeout: 10000 });
|
||||
});
|
||||
|
||||
test('não deve modificar turma da atribuição', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/assignments/edit/assignment-id');
|
||||
|
||||
const classSelect = page.getByRole('combobox', { name: /turma/i });
|
||||
const isDisabled = await classSelect.isDisabled();
|
||||
|
||||
// Geralmente não permite mudar a turma
|
||||
expect(isDisabled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Excluir Atribuição', () => {
|
||||
test('deve confirmar antes de excluir', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/assignments');
|
||||
|
||||
const deleteButton = page.getByRole('button', { name: /excluir/i }).first();
|
||||
if (await deleteButton.isVisible()) {
|
||||
await deleteButton.click();
|
||||
|
||||
await expect(page.getByText(/tem certeza|deseja excluir/i)).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: /confirmar|sim/i })).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: /cancelar|não/i })).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve remover atribuição após excluir', async ({ page }) => {
|
||||
// TODO: Implementar
|
||||
// const beforeCount = await page.locator('[data-testid="assignment-row"]').count();
|
||||
|
||||
// await page.getByRole('button', { name: /excluir/i }).first().click();
|
||||
// await page.getByRole('button', { name: /confirmar/i }).click();
|
||||
|
||||
// await expect(page.locator('[data-testid="assignment-row"]').count()).toBe(beforeCount - 1);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Status da Atribuição', () => {
|
||||
test('deve mostrar status da atribuição', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/assignments');
|
||||
|
||||
// Status possíveis: draft, active, expired
|
||||
const statusBadge = page.locator('[data-testid="status-badge"]').first();
|
||||
if (await statusBadge.isVisible()) {
|
||||
await expect(statusBadge).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve mostrar atribuições expiradas separadas', async ({ page }) => {
|
||||
// Pode ter filtro ou aba para expiradas
|
||||
const expiredFilter = page.getByRole('tab', { name: /expiradas/i });
|
||||
if (await expiredFilter.isVisible()) {
|
||||
await expiredFilter.click();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve mostrar número de alunos que fizeram a prova', async ({ page }) => {
|
||||
const assignmentRow = page.locator('tr').nth(1);
|
||||
if (await assignmentRow.isVisible()) {
|
||||
await expect(assignmentRow.getByText(/\d+\/\d+/)).toBeVisible(); // Ex: 5/18
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Duplicar Atribuição', () => {
|
||||
test('deve permitir duplicar atribuição existente', async ({ page }) => {
|
||||
// TODO: Testar duplicação
|
||||
// await page.goto('/admin/dashboard/assignments');
|
||||
// await page.getByRole('button', { name: /duplicar/i }).first().click();
|
||||
|
||||
// await expect(page.getByLabel(/título/i)).toContainText('cópia');
|
||||
// await page.getByRole('button', { name: /criar/i }).click();
|
||||
|
||||
// Deve criar nova atribuição com mesmos dados
|
||||
});
|
||||
|
||||
test('deve incrementar nome ao duplicar', async ({ page }) => {
|
||||
// TODO: Testar se nome é incrementado automaticamente
|
||||
// await page.getByRole('button', { name: /duplicar/i }).first().click();
|
||||
|
||||
// const nameField = page.getByLabel(/título/i);
|
||||
// const originalName = await nameField.inputValue();
|
||||
// await expect(originalName).toMatch(/\(2\)|cópia/i);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Visualização do Template', () => {
|
||||
test('deve mostrar preview do template ao selecionar', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/assignments/add');
|
||||
|
||||
const templateSelect = page.getByRole('combobox', { name: /template/i });
|
||||
if ((await templateSelect.locator('option').count()) > 0) {
|
||||
await templateSelect.selectOption({ index: 0 });
|
||||
|
||||
// Pode mostrar número de questões
|
||||
// await expect(page.getByText(/\d+ questões/i)).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve linkar para página do template', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/assignments/add');
|
||||
|
||||
const templateLink = page.getByRole('link', { name: /ver template/i });
|
||||
if (await templateLink.isVisible()) {
|
||||
await templateLink.click();
|
||||
|
||||
await expect(page).toHaveURL(/\/exam-templates/i);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,163 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('Admin - Categorias', () => {
|
||||
// TODO: Fazer login como admin
|
||||
// test.beforeEach(async ({ page }) => {
|
||||
// await page.goto('/auth/login');
|
||||
// await page.getByLabel(/email/i).fill('[email protected]');
|
||||
// await page.getByLabel(/senha/i).fill('123456');
|
||||
// await page.getByRole('button', { name: /entrar/i }).click();
|
||||
// await page.waitForURL(/\/admin\/dashboard/);
|
||||
// });
|
||||
|
||||
test.describe('Lista de Categorias', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/categories');
|
||||
});
|
||||
|
||||
test('deve mostrar lista de categorias', async ({ page }) => {
|
||||
await expect(page.getByText(/categorias|categories/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve mostrar cor de cada categoria', async ({ page }) => {
|
||||
const categoryCard = page.locator('[data-testid="category-card"], .card').first();
|
||||
if (await categoryCard.isVisible()) {
|
||||
// Deve ter badge/cor visual
|
||||
const colorBadge = categoryCard.locator('[class*="bg-"]').first();
|
||||
await expect(colorBadge).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve ter botão de adicionar nova categoria', async ({ page }) => {
|
||||
await expect(page.getByRole('link', { name: /adicionar|nova|criar/i })).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Criar Nova Categoria', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/categories/add');
|
||||
});
|
||||
|
||||
test('deve mostrar formulário de criação', async ({ page }) => {
|
||||
await expect(page.getByLabel(/nome|name/i)).toBeVisible();
|
||||
await expect(page.getByText(/cor|color/i)).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: /salvar|criar/i })).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve ter opções de cor para selecionar', async ({ page }) => {
|
||||
// Deve ter seletor de cores ou botões de cor
|
||||
const colorSelector = page.getByRole('combobox', { name: /cor|color/i });
|
||||
const colorButtons = page.locator('[class*="bg-emerald-"], [class*="bg-blue-"], [class*="bg-red-"]');
|
||||
|
||||
const hasColorOption = await colorSelector.isVisible() || (await colorButtons.count()) > 0;
|
||||
expect(hasColorOption).toBe(true);
|
||||
});
|
||||
|
||||
test('deve criar categoria com dados válidos', async ({ page }) => {
|
||||
const timestamp = Date.now();
|
||||
|
||||
await page.getByLabel(/nome|name/i).fill(`Categoria ${timestamp}`);
|
||||
|
||||
// Selecionar cor
|
||||
const colorSelector = page.getByRole('combobox', { name: /cor|color/i });
|
||||
if (await colorSelector.isVisible()) {
|
||||
await colorSelector.selectOption({ index: 0 });
|
||||
}
|
||||
|
||||
await page.getByRole('button', { name: /salvar|criar/i }).click();
|
||||
|
||||
// Deve redirecionar para lista ou mostrar sucesso
|
||||
await expect(page).toHaveURL(/\/admin\/dashboard\/categories/, { timeout: 10000 });
|
||||
});
|
||||
|
||||
test('deve validar nome obrigatório', async ({ page }) => {
|
||||
await page.getByRole('button', { name: /salvar|criar/i }).click();
|
||||
|
||||
await expect(page.getByText(/nome.*obrigatório|required/i)).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Editar Categoria', () => {
|
||||
test('deve carregar dados da categoria', async ({ page }) => {
|
||||
// TODO: Usar ID de categoria de teste
|
||||
await page.goto('/admin/dashboard/categories/edit/category-id');
|
||||
|
||||
await expect(page.getByLabel(/nome|name/i)).not.toBeEmpty();
|
||||
});
|
||||
|
||||
test('deve permitir modificar nome e cor', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/categories/edit/category-id');
|
||||
|
||||
await page.getByLabel(/nome|name/i).fill('Categoria Editada');
|
||||
|
||||
const colorSelector = page.getByRole('combobox', { name: /cor|color/i });
|
||||
if (await colorSelector.isVisible()) {
|
||||
await colorSelector.selectOption({ index: 1 });
|
||||
}
|
||||
|
||||
await page.getByRole('button', { name: /salvar|atualizar/i }).click();
|
||||
|
||||
await expect(page).toHaveURL(/\/admin\/dashboard\/categories/, { timeout: 10000 });
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Excluir Categoria', () => {
|
||||
test('deve confirmar antes de excluir', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/categories');
|
||||
|
||||
const deleteButton = page.getByRole('button', { name: /excluir|delete/i }).first();
|
||||
if (await deleteButton.isVisible()) {
|
||||
await deleteButton.click();
|
||||
|
||||
await expect(page.getByText(/tem certeza|deseja excluir/i)).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: /confirmar|sim/i })).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: /cancelar|não/i })).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve excluir categoria sem arquivos vinculados', async ({ page }) => {
|
||||
// TODO: Criar categoria sem arquivos e excluir
|
||||
// await page.goto('/admin/dashboard/categories');
|
||||
// await page.getByRole('button', { name: /excluir/i }).first().click();
|
||||
// await page.getByRole('button', { name: /confirmar/i }).click();
|
||||
|
||||
// await expect(page.getByText(/categoria excluída|sucesso/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('não deve excluir categoria com arquivos vinculados', async ({ page }) => {
|
||||
// TODO: Tentar excluir categoria em uso
|
||||
// await page.goto('/admin/dashboard/categories/edit/used-category');
|
||||
// await page.getByRole('button', { name: /excluir/i }).click();
|
||||
// await page.getByRole('button', { name: /confirmar/i }).click();
|
||||
|
||||
// await expect(page.getByText(/possui arquivos|em uso|vinculada/i)).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Cores de Categoria', () => {
|
||||
test('deve ter múltiplas opções de cor', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/categories/add');
|
||||
|
||||
const colorSelector = page.getByRole('combobox', { name: /cor|color/i });
|
||||
if (await colorSelector.isVisible()) {
|
||||
const options = await colorSelector.locator('option').count();
|
||||
expect(options).toBeGreaterThan(1);
|
||||
}
|
||||
});
|
||||
|
||||
test('deve mostrar preview da cor selecionada', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/categories/add');
|
||||
|
||||
const colorSelector = page.getByRole('combobox', { name: /cor|color/i });
|
||||
if (await colorSelector.isVisible()) {
|
||||
await colorSelector.selectOption({ index: 0 });
|
||||
|
||||
// Pode haver um preview visual
|
||||
const colorPreview = page.locator('[class*="rounded-full"][class*="bg-"]').first();
|
||||
if (await colorPreview.isVisible()) {
|
||||
await expect(colorPreview).toBeVisible();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,155 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('Admin - Tipos de Classe (ClassTypes)', () => {
|
||||
// TODO: Fazer login como admin
|
||||
// test.beforeEach(async ({ page }) => {
|
||||
// await page.goto('/auth/login');
|
||||
// await page.getByLabel(/email/i).fill('[email protected]');
|
||||
// await page.getByLabel(/senha/i).fill('123456');
|
||||
// await page.getByRole('button', { name: /entrar/i }).click();
|
||||
// await page.waitForURL(/\/admin\/dashboard/);
|
||||
// });
|
||||
|
||||
test.describe('Lista de ClassTypes', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/classTypes');
|
||||
});
|
||||
|
||||
test('deve mostrar lista de tipos de classe', async ({ page }) => {
|
||||
await expect(page.getByText(/tipos de classe|class types/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve ter botão de adicionar novo tipo', async ({ page }) => {
|
||||
await expect(page.getByRole('link', { name: /adicionar|novo|criar/i })).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve mostrar nome, preço e ações de cada tipo', async ({ page }) => {
|
||||
const typeCard = page.locator('[data-testid="classtype-card"], .card').first();
|
||||
if (await typeCard.isVisible()) {
|
||||
await expect(typeCard.getByText(/preço|price/i)).toBeVisible();
|
||||
await expect(typeCard.getByRole('link', { name: /editar/i })).toBeVisible();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Criar Novo ClassType', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/classTypes/add');
|
||||
});
|
||||
|
||||
test('deve mostrar formulário de criação', async ({ page }) => {
|
||||
await expect(page.getByLabel(/nome|name/i)).toBeVisible();
|
||||
await expect(page.getByLabel(/preço|price/i)).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: /salvar|criar/i })).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve criar tipo com dados válidos', async ({ page }) => {
|
||||
const timestamp = Date.now();
|
||||
|
||||
await page.getByLabel(/nome|name/i).fill(`Tipo Teste ${timestamp}`);
|
||||
await page.getByLabel(/preço|price/i).fill('150,00');
|
||||
|
||||
await page.getByRole('button', { name: /salvar|criar/i }).click();
|
||||
|
||||
// Deve redirecionar para lista ou mostrar sucesso
|
||||
await expect(page).toHaveURL(/\/admin\/dashboard\/classTypes/, { timeout: 10000 });
|
||||
});
|
||||
|
||||
test('deve validar campo nome obrigatório', async ({ page }) => {
|
||||
await page.getByRole('button', { name: /salvar|criar/i }).click();
|
||||
|
||||
await expect(page.getByText(/nome.*obrigatório|required/i)).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Editar ClassType', () => {
|
||||
test('deve carregar dados do tipo', async ({ page }) => {
|
||||
// TODO: Usar ID de classType de teste
|
||||
await page.goto('/admin/dashboard/classTypes/edit/67ca5e4cfb41e291a99a7a28');
|
||||
|
||||
await expect(page.getByLabel(/nome|name/i)).not.toBeEmpty();
|
||||
});
|
||||
|
||||
test('deve permitir modificar dados', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/classTypes/edit/67ca5e4cfb41e291a99a7a28');
|
||||
|
||||
const originalName = await page.getByLabel(/nome|name/i).inputValue();
|
||||
await page.getByLabel(/nome|name/i).fill(`${originalName} (Editado)`);
|
||||
|
||||
await page.getByRole('button', { name: /salvar|atualizar/i }).click();
|
||||
|
||||
await expect(page).toHaveURL(/\/admin\/dashboard\/classTypes/, { timeout: 10000 });
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Excluir ClassType', () => {
|
||||
test('deve confirmar exclusão', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/classTypes');
|
||||
|
||||
const deleteButton = page.getByRole('button', { name: /excluir|delete/i }).first();
|
||||
if (await deleteButton.isVisible()) {
|
||||
await deleteButton.click();
|
||||
|
||||
// Deve pedir confirmação
|
||||
await expect(page.getByText(/tem certeza|deseja excluir/i)).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: /confirmar|sim/i })).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: /cancelar|não/i })).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('não deve excluir se há turmas vinculadas', async ({ page }) => {
|
||||
// TODO: Tentar excluir classType que tem turmas
|
||||
// await page.goto('/admin/dashboard/classTypes/edit/used-id');
|
||||
// await page.getByRole('button', { name: /excluir/i }).click();
|
||||
// await page.getByRole('button', { name: /confirmar/i }).click();
|
||||
|
||||
// await expect(page.getByText(/possui turmas|em uso/i)).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Arquivos do ClassType', () => {
|
||||
test('deve mostrar arquivos vinculados', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/classTypes/files/67ca5e4cfb41e291a99a7a28');
|
||||
|
||||
await expect(page.getByText(/arquivos|files/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve permitir adicionar arquivos', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/classTypes/files/67ca5e4cfb41e291a99a7a28');
|
||||
|
||||
const addButton = page.getByRole('link', { name: /adicionar|upload/i }).first();
|
||||
if (await addButton.isVisible()) {
|
||||
await addButton.click();
|
||||
await expect(page).toHaveURL(/\/files\/add/i);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Preço Padrão', () => {
|
||||
test('deve aceitar formato decimal com vírgula', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/classTypes/add');
|
||||
|
||||
await page.getByLabel(/preço|price/i).fill('150,50');
|
||||
|
||||
// Não deve mostrar erro de formato
|
||||
await page.getByRole('button', { name: /salvar/i }).click();
|
||||
// Pode mostrar erro de outros campos obrigatórios
|
||||
});
|
||||
|
||||
test('deve aceitar formato decimal com ponto', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/classTypes/add');
|
||||
|
||||
await page.getByLabel(/preço|price/i).fill('150.50');
|
||||
|
||||
await page.getByRole('button', { name: /salvar/i }).click();
|
||||
});
|
||||
|
||||
test('deve aceitar preço zero ou vazio', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/classTypes/add');
|
||||
|
||||
await page.getByLabel(/preço|price/i).fill('0');
|
||||
|
||||
await page.getByRole('button', { name: /salvar/i }).click();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,195 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('Admin - Turmas (Classes)', () => {
|
||||
// TODO: Fazer login como admin antes de cada teste
|
||||
// test.beforeEach(async ({ page }) => {
|
||||
// await page.goto('/auth/login');
|
||||
// await page.getByLabel(/email/i).fill('[email protected]');
|
||||
// await page.getByLabel(/senha/i).fill('123456');
|
||||
// await page.getByRole('button', { name: /entrar/i }).click();
|
||||
// await page.waitForURL(/\/admin\/dashboard/);
|
||||
// });
|
||||
|
||||
test.describe('Lista de Turmas', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/class');
|
||||
});
|
||||
|
||||
test('deve mostrar lista de turmas', async ({ page }) => {
|
||||
await expect(page.getByText(/turmas|classes/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve ter botão de adicionar nova turma', async ({ page }) => {
|
||||
await expect(page.getByRole('link', { name: /adicionar|nova|criar/i })).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve ter busca funcionando', async ({ page }) => {
|
||||
const searchInput = page.getByPlaceholder(/buscar|pesquisar|search/i);
|
||||
if (await searchInput.isVisible()) {
|
||||
await searchInput.fill('Inglês');
|
||||
await page.waitForTimeout(500);
|
||||
// Verificar se filtrou
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Criar Nova Turma', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/class/add');
|
||||
});
|
||||
|
||||
test('deve mostrar formulário de criação', async ({ page }) => {
|
||||
await expect(page.getByLabel(/tipo de classe|class type/i)).toBeVisible();
|
||||
await expect(page.getByLabel(/título/i)).toBeVisible();
|
||||
await expect(page.getByLabel(/data de início|start date/i)).toBeVisible();
|
||||
await expect(page.getByLabel(/horário|time/i)).toBeVisible();
|
||||
await expect(page.getByText(/dias da semana/i)).toBeVisible();
|
||||
await expect(page.getByText(/professores/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve validar campos obrigatórios', async ({ page }) => {
|
||||
await page.getByRole('button', { name: /salvar|criar/i }).click();
|
||||
|
||||
await expect(page.getByText(/obrigatório|required/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve validar data de término posterior a data de início', async ({ page }) => {
|
||||
await page.getByLabel(/data de início/i).fill('2025-01-10');
|
||||
await page.getByLabel(/data de término|end date/i).fill('2025-01-01');
|
||||
await page.getByRole('button', { name: /salvar|criar/i }).click();
|
||||
|
||||
await expect(page.getByText(/término não pode ser anterior|data inválida/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve criar turma com dados válidos', async ({ page }) => {
|
||||
const timestamp = Date.now();
|
||||
|
||||
// Selecionar tipo de classe
|
||||
await page.getByLabel(/tipo de classe/i).selectOption({ index: 0 });
|
||||
|
||||
// Preencher título
|
||||
await page.getByLabel(/título/i).fill(`Turma Teste ${timestamp}`);
|
||||
|
||||
// Data de início
|
||||
await page.getByLabel(/data de início/i).fill('2025-01-01');
|
||||
|
||||
// Horário
|
||||
await page.getByLabel(/horário/i).fill('19:00');
|
||||
|
||||
// Selecionar professores
|
||||
const teacherCheckbox = page.locator('input[type="checkbox"]').first();
|
||||
if (await teacherCheckbox.isVisible()) {
|
||||
await teacherCheckbox.check();
|
||||
}
|
||||
|
||||
// Selecionar dias da semana
|
||||
await page.getByText(/seg/i).click();
|
||||
|
||||
// Salvar
|
||||
await page.getByRole('button', { name: /salvar|criar/i }).click();
|
||||
|
||||
// Deve redirecionar para lista
|
||||
await expect(page).toHaveURL(/\/admin\/dashboard\/class/, { timeout: 15000 });
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Editar Turma Existente', () => {
|
||||
test('deve carregar dados da turma', async ({ page }) => {
|
||||
// TODO: Usar ID de turma de teste
|
||||
await page.goto('/admin/dashboard/class/edit/6975e7cfb41e291a99a79ece');
|
||||
|
||||
await expect(page.getByLabel(/título/i)).not.toBeEmpty();
|
||||
});
|
||||
|
||||
test('deve permitir modificar professores', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/class/edit/6975e7cfb41e291a99a79ece');
|
||||
|
||||
// Desmarcar professor selecionado
|
||||
const checkedTeacher = page.locator('input[type="checkbox"]:checked').first();
|
||||
if (await checkedTeacher.isVisible()) {
|
||||
await checkedTeacher.uncheck();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve permitir adicionar alunos via select', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/class/edit/6975e7cfb41e291a99a79ece');
|
||||
|
||||
const studentSelect = page.getByRole('combobox').filter({ hasText: /adicionar aluno/i });
|
||||
if (await studentSelect.isVisible()) {
|
||||
// Selecionar primeiro aluno disponível
|
||||
await studentSelect.selectOption({ index: 1 });
|
||||
|
||||
// Verificar se apareceu tag do aluno
|
||||
await expect(page.locator('.student-tag')).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve permitir remover aluno da seleção', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/class/edit/6975e7cfb41e291a99a79ece');
|
||||
|
||||
// Se há tags de alunos, tentar remover
|
||||
const studentTag = page.locator('.student-tag').first();
|
||||
if (await studentTag.isVisible()) {
|
||||
await studentTag.getByRole('button').click();
|
||||
// Verificar se foi removido
|
||||
}
|
||||
});
|
||||
|
||||
test('deve salvar alterações com sucesso', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/class/edit/6975e7cfb41e291a99a79ece');
|
||||
|
||||
const originalTitle = await page.getByLabel(/título/i).inputValue();
|
||||
await page.getByLabel(/título/i).fill(`${originalTitle} (editado)`);
|
||||
|
||||
await page.getByRole('button', { name: /salvar|atualizar/i }).click();
|
||||
|
||||
await expect(page).toHaveURL(/\/admin\/dashboard\/class/, { timeout: 15000 });
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Dias da Semana - Checkbox', () => {
|
||||
test('deve mostrar todos os dias', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/class/add');
|
||||
|
||||
const days = ['Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sab', 'Dom'];
|
||||
for (const day of days) {
|
||||
await expect(page.getByText(day, { exact: true })).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve permitir selecionar múltiplos dias', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/class/add');
|
||||
|
||||
await page.getByText('Seg').click();
|
||||
await page.getByText('Qua').click();
|
||||
await page.getByText('Sex').click();
|
||||
|
||||
// Verificar se estão marcados
|
||||
const segCheckbox = page.getByText('Seg').locator('input[type="checkbox"]');
|
||||
await expect(segCheckbox).toBeChecked();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Professores - Checkbox', () => {
|
||||
test('deve mostrar lista de professores disponíveis', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/class/add');
|
||||
|
||||
await expect(page.getByText(/professores/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve permitir selecionar múltiplos professores', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/class/add');
|
||||
|
||||
const checkboxes = page.locator('input[type="checkbox"]');
|
||||
const count = await checkboxes.count();
|
||||
|
||||
if (count >= 2) {
|
||||
await checkboxes.nth(0).check();
|
||||
await checkboxes.nth(1).check();
|
||||
|
||||
await expect(checkboxes.nth(0)).toBeChecked();
|
||||
await expect(checkboxes.nth(1)).toBeChecked();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,328 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('Admin - Templates de Prova', () => {
|
||||
// TODO: Fazer login como admin
|
||||
// test.beforeEach(async ({ page }) => {
|
||||
// await page.goto('/auth/login');
|
||||
// await page.getByLabel(/email/i).fill('[email protected]');
|
||||
// await page.getByLabel(/senha/i).fill('123456');
|
||||
// await page.getByRole('button', { name: /entrar/i }).click();
|
||||
// await page.waitForURL(/\/dispatcher/);
|
||||
// await page.getByRole('button', { name: /admin/i }).click();
|
||||
// });
|
||||
|
||||
test.describe('Lista de Templates', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/exam-templates');
|
||||
});
|
||||
|
||||
test('deve mostrar lista de templates', async ({ page }) => {
|
||||
await expect(page.getByText(/templates|modelos/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve ter botão de criar novo template', async ({ page }) => {
|
||||
await expect(page.getByRole('button', { name: /novo|criar/i })).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve mostrar informações do template', async ({ page }) => {
|
||||
const templateCard = page.locator('[data-testid="template-card"], .card').first();
|
||||
if (await templateCard.isVisible()) {
|
||||
await expect(templateCard.getByText(/questões|questions/i)).toBeVisible();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Criar Novo Template', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// Abrir modal de criação
|
||||
await page.goto('/admin/dashboard/exam-templates');
|
||||
await page.getByRole('button', { name: /novo|criar/i }).click();
|
||||
});
|
||||
|
||||
test('deve mostrar modal de criação', async ({ page }) => {
|
||||
await expect(page.locator('.fixed.inset-0')).toBeVisible();
|
||||
await expect(page.getByText(/novo template|criar template/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve ter campos básicos', async ({ page }) => {
|
||||
await expect(page.getByLabel(/título|title/i)).toBeVisible();
|
||||
await expect(page.getByPlaceholder(/breve descrição/i)).toBeVisible();
|
||||
await expect(page.getByPlaceholder(/instruções/i)).toBeVisible();
|
||||
await expect(page.getByLabel(/tempo limite|time limit/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve ter seção de questões', async ({ page }) => {
|
||||
await expect(page.getByText(/questões|questions/i)).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: /adicionar questão/i })).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve ter checkbox "público"', async ({ page }) => {
|
||||
await expect(page.getByRole('checkbox', { name: /público|public/i })).toBeVisible();
|
||||
await expect(page.getByText(/outros professores podem usar/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve salvar template mínimo', async ({ page }) => {
|
||||
const timestamp = Date.now();
|
||||
|
||||
await page.getByLabel(/título|title/i).fill(`Template ${timestamp}`);
|
||||
await page.getByLabel(/tempo limite|time limit/i).fill('60');
|
||||
|
||||
await page.getByRole('button', { name: /criar|salvar/i }).click();
|
||||
|
||||
// Deve fechar modal
|
||||
await expect(page.locator('.fixed.inset-0')).not.toBeVisible({ timeout: 5000 });
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Adicionar Questões', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/exam-templates');
|
||||
await page.getByRole('button', { name: /novo/i }).click();
|
||||
await page.getByLabel(/título|title/i).fill('Template com Questões');
|
||||
});
|
||||
|
||||
test('deve adicionar questão de múltipla escolha', async ({ page }) => {
|
||||
await page.getByRole('button', { name: /adicionar questão/i }).click();
|
||||
|
||||
// Deve mostrar nova seção de questão
|
||||
await expect(page.getByText(/questão \d+/i)).toBeVisible();
|
||||
await expect(page.getByRole('combobox', { name: /tipo/i })).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve alterar tipo da questão', async ({ page }) => {
|
||||
await page.getByRole('button', { name: /adicionar questão/i }).click();
|
||||
|
||||
const typeSelect = page.getByRole('combobox').filter({ hasText: /tipo/i }).first();
|
||||
await typeSelect.selectOption('text');
|
||||
|
||||
// Não deve mais mostrar opções de múltipla escolha
|
||||
await expect(page.getByText(/opções de resposta/i)).not.toBeVisible();
|
||||
await expect(page.getByText(/será corrigida manualmente/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve preencher enunciado obrigatório', async ({ page }) => {
|
||||
await page.getByRole('button', { name: /adicionar questão/i }).click();
|
||||
|
||||
await page.getByPlaceholder(/enunciado/i).fill('Qual é a capital do Brasil?');
|
||||
|
||||
await page.getByRole('button', { name: /criar|salvar/i }).click();
|
||||
|
||||
// Pode mostrar erro de questões vazias
|
||||
});
|
||||
|
||||
test('deve adicionar opções à questão de múltipla escolha', async ({ page }) => {
|
||||
await page.getByRole('button', { name: /adicionar questão/i }).click();
|
||||
|
||||
// Já deve vir com 2 opções
|
||||
await expect(page.getByPlaceholder(/opção \d+/i).nth(0)).toBeVisible();
|
||||
await expect(page.getByPlaceholder(/opção \d+/i).nth(1)).toBeVisible();
|
||||
|
||||
// Adicionar terceira opção
|
||||
await page.getByRole('button', { name: /adicionar opção/i }).click();
|
||||
await expect(page.getByPlaceholder(/opção \d+/i).nth(2)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve marcar opção correta', async ({ page }) => {
|
||||
await page.getByRole('button', { name: /adicionar questão/i }).click();
|
||||
|
||||
const correctRadio = page.locator('input[type="radio"]').first();
|
||||
await correctRadio.check();
|
||||
|
||||
await expect(correctRadio).toBeChecked();
|
||||
});
|
||||
|
||||
test('deve remover opção', async ({ page }) => {
|
||||
await page.getByRole('button', { name: /adicionar questão/i }).click();
|
||||
await page.getByRole('button', { name: /adicionar opção/i }).click();
|
||||
|
||||
// Remover segunda opção
|
||||
const deleteButtons = page.getByRole('button', { name: /excluir|remover/i, exact: true });
|
||||
const count = await deleteButtons.count();
|
||||
|
||||
if (count >= 2) {
|
||||
await deleteButtons.nth(1).click();
|
||||
|
||||
// Deve voltar a ter 2 opções (mínimo)
|
||||
await expect(page.getByPlaceholder(/opção \d+/i).nth(0)).toBeVisible();
|
||||
await expect(page.getByPlaceholder(/opção \d+/i).nth(1)).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve remover questão', async ({ page }) => {
|
||||
await page.getByRole('button', { name: /adicionar questão/i }).click();
|
||||
|
||||
const deleteQuestionButton = page.locator('[data-testid="question-card"]').first()
|
||||
.getByRole('button', { name: /excluir|lixeira/i });
|
||||
|
||||
if (await deleteQuestionButton.isVisible()) {
|
||||
const beforeCount = await page.locator('[data-testid="question-card"]').count();
|
||||
|
||||
await deleteQuestionButton.click();
|
||||
|
||||
const afterCount = await page.locator('[data-testid="question-card"]').count();
|
||||
expect(afterCount).toBe(beforeCount - 1);
|
||||
}
|
||||
});
|
||||
|
||||
test('deve validar mínimo de 2 opções para múltipla escolha', async ({ page }) => {
|
||||
await page.getByRole('button', { name: /adicionar questão/i }).click();
|
||||
|
||||
// Remover opções até ter menos de 2
|
||||
const deleteButton = page.getByRole('button', { name: /excluir opção/i });
|
||||
const deleteCount = await deleteButton.count();
|
||||
|
||||
if (deleteCount >= 2) {
|
||||
await deleteButton.nth(0).click();
|
||||
await deleteButton.nth(0).click();
|
||||
|
||||
await page.getByRole('button', { name: /criar|salvar/i }).click();
|
||||
|
||||
await expect(page.getByText(/mínimo \d+ opções|pelo menos 2 opções/i)).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve definir pontos da questão', async ({ page }) => {
|
||||
await page.getByRole('button', { name: /adicionar questão/i }).click();
|
||||
|
||||
const pointsInput = page.getByRole('spinbutton', { name: /pontos/i });
|
||||
if (await pointsInput.isVisible()) {
|
||||
await pointsInput.fill('5');
|
||||
|
||||
const value = await pointsInput.inputValue();
|
||||
expect(value).toBe('5');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Editar Template', () => {
|
||||
test('deve carregar dados do template', async ({ page }) => {
|
||||
// TODO: Editar template existente
|
||||
await page.goto('/admin/dashboard/exam-templates');
|
||||
await page.getByRole('button', { name: /editar/i }).first().click();
|
||||
|
||||
await expect(page.getByLabel(/título|title/i)).not.toBeEmpty();
|
||||
});
|
||||
|
||||
test('deve carregar questões existentes', async ({ page }) => {
|
||||
// TODO: Template com questões
|
||||
await page.goto('/admin/dashboard/exam-templates/edit/template-id');
|
||||
|
||||
const questionCards = page.locator('[data-testid="question-card"]');
|
||||
const count = await questionCards.count();
|
||||
|
||||
if (count > 0) {
|
||||
await expect(questionCards.nth(0).getByPlaceholder(/enunciado/i)).not.toBeEmpty();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Excluir Template', () => {
|
||||
test('deve confirmar antes de excluir', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/exam-templates');
|
||||
|
||||
const deleteButton = page.getByRole('button', { name: /excluir/i }).first();
|
||||
if (await deleteButton.isVisible()) {
|
||||
await deleteButton.click();
|
||||
|
||||
await expect(page.getByText(/tem certeza|deseja excluir/i)).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('não deve excluir se há tentativas', async ({ page }) => {
|
||||
// TODO: Tentar excluir template usado
|
||||
// await page.goto('/admin/dashboard/exam-templates/edit/used-template');
|
||||
// await page.getByRole('button', { name: /excluir/i }).click();
|
||||
// await page.getByRole('button', { name: /confirmar/i }).click();
|
||||
|
||||
// await expect(page.getByText(/possui tentativas|em uso/i)).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Template Público', () => {
|
||||
test('deve marcar como público', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/exam-templates');
|
||||
await page.getByRole('button', { name: /novo/i }).click();
|
||||
|
||||
await page.getByRole('checkbox', { name: /público/i }).check();
|
||||
|
||||
await page.getByLabel(/título|title/i).fill('Template Público Teste');
|
||||
|
||||
await page.getByRole('button', { name: /criar/i }).click();
|
||||
});
|
||||
|
||||
test('template público deve aparecer para professores', async ({ page }) => {
|
||||
// TODO: Fazer login como professor e verificar se template público aparece
|
||||
// await page.goto('/auth/login');
|
||||
// await page.getByLabel(/email/i).fill('[email protected]');
|
||||
// await page.getByLabel(/senha/i).fill('123456');
|
||||
// await page.getByRole('button', { name: /entrar/i }).click();
|
||||
|
||||
// await page.goto('/dashboard/teacher/exam-templates');
|
||||
|
||||
// await expect(page.getByText(/Template Público Teste/i)).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Tags e Categoria', () => {
|
||||
test('deve aceitar tags separadas por vírgula', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/exam-templates');
|
||||
await page.getByRole('button', { name: /novo/i }).click();
|
||||
|
||||
await page.getByLabel(/tags/i).fill('básico, revisão, unidade 1');
|
||||
|
||||
await page.getByLabel(/título|title/i).fill('Template com Tags');
|
||||
await page.getByRole('button', { name: /criar/i }).click();
|
||||
|
||||
// Editar para verificar se tags foram salvas
|
||||
// await page.getByRole('button', { name: /editar/i }).first().click();
|
||||
// await expect(page.getByRole('textbox', { name: /tags/i })).toHaveValue(/básico|revisão/);
|
||||
});
|
||||
|
||||
test('deve aceitar categoria', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/exam-templates');
|
||||
await page.getByRole('button', { name: /novo/i }).click();
|
||||
|
||||
await page.getByLabel(/categoria/i).fill('Inglês');
|
||||
|
||||
await page.getByLabel(/título|title/i).fill('Template com Categoria');
|
||||
await page.getByRole('button', { name: /criar/i }).click();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Modal do Template', () => {
|
||||
test('deve fechar ao clicar no X', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/exam-templates');
|
||||
await page.getByRole('button', { name: /novo/i }).click();
|
||||
|
||||
await expect(page.locator('.fixed.inset-0')).toBeVisible();
|
||||
|
||||
await page.getByRole('button', { name: /✕|fechar/i }).click();
|
||||
|
||||
await expect(page.locator('.fixed.inset-0')).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('deve fechar ao clicar fora do modal', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/exam-templates');
|
||||
await page.getByRole('button', { name: /novo/i }).click();
|
||||
|
||||
const modal = page.locator('.bg-white.dark\\:bg-neutral-900');
|
||||
const box = await modal.boundingBox();
|
||||
|
||||
// Clicar fora
|
||||
await page.mouse.click(box.x - 10, box.y);
|
||||
|
||||
await expect(page.locator('.fixed.inset-0')).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('botão cancelar deve fechar sem salvar', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/exam-templates');
|
||||
await page.getByRole('button', { name: /novo/i }).click();
|
||||
|
||||
await page.getByLabel(/título|title/i).fill('Template Cancelado');
|
||||
|
||||
await page.getByRole('button', { name: /cancelar/i }).click();
|
||||
|
||||
await expect(page.locator('.fixed.inset-0')).not.toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,271 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('Admin - Arquivos/Files', () => {
|
||||
// TODO: Fazer login como admin
|
||||
// test.beforeEach(async ({ page }) => {
|
||||
// await page.goto('/auth/login');
|
||||
// await page.getByLabel(/email/i).fill('[email protected]');
|
||||
// await page.getByLabel(/senha/i).fill('123456');
|
||||
// await page.getByRole('button', { name: /entrar/i }).click();
|
||||
// await page.waitForURL(/\/admin\/dashboard/);
|
||||
// });
|
||||
|
||||
test.describe('Lista de Arquivos', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/files');
|
||||
});
|
||||
|
||||
test('deve mostrar lista de arquivos', async ({ page }) => {
|
||||
await expect(page.getByText(/arquivos|files/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve ter botão de upload', async ({ page }) => {
|
||||
await expect(page.getByRole('link', { name: /upload|adicionar|novo/i })).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve mostrar informações do arquivo', async ({ page }) => {
|
||||
const fileRow = page.locator('tr').nth(1); // Pular header
|
||||
if (await fileRow.isVisible()) {
|
||||
await expect(fileRow.getByText(/\.(pdf|doc|png|jpg)/i)).toBeVisible();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Upload de Arquivo', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/files/add');
|
||||
});
|
||||
|
||||
test('deve mostrar formulário de upload', async ({ page }) => {
|
||||
await expect(page.getByLabelText(/título|title/i)).toBeVisible();
|
||||
await expect(page.getByLabelText(/arquivo|file/i)).toBeVisible();
|
||||
await expect(page.getByRole('combobox', { name: /categoria/i })).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: /upload|salvar/i })).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve aceitar upload de arquivo PDF', async ({ page }) => {
|
||||
// TODO: Criar arquivo PDF temporário
|
||||
// const fileInput = page.getByLabelText(/arquivo/i);
|
||||
// await fileInput.setInputFiles('tests/fixtures/test.pdf');
|
||||
|
||||
await page.getByLabelText(/título|title/i).fill('Arquivo Teste PDF');
|
||||
|
||||
const categorySelect = page.getByRole('combobox', { name: /categoria/i });
|
||||
if (await categorySelect.isVisible()) {
|
||||
await categorySelect.selectOption({ index: 0 });
|
||||
}
|
||||
|
||||
// await page.getByRole('button', { name: /upload|salvar/i }).click();
|
||||
// await expect(page).toHaveURL(/\/admin\/dashboard\/files/, { timeout: 15000 });
|
||||
});
|
||||
|
||||
test('deve aceitar upload de arquivo de imagem', async ({ page }) => {
|
||||
// const fileInput = page.getByLabelText(/arquivo/i);
|
||||
// await fileInput.setInputFiles('tests/fixtures/test.png');
|
||||
|
||||
await page.getByLabelText(/título|title/i).fill('Imagem Teste');
|
||||
|
||||
// await page.getByRole('button', { name: /upload|salvar/i }).click();
|
||||
});
|
||||
|
||||
test('deve validar título obrigatório', async ({ page }) => {
|
||||
await page.getByRole('button', { name: /upload|salvar/i }).click();
|
||||
|
||||
await expect(page.getByText(/título.*obrigatório|title.*required/i)).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Upload por Turma', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// TODO: Usar ID de turma de teste
|
||||
await page.goto('/files/class/class-id/add');
|
||||
});
|
||||
|
||||
test('deve pré-selecionar turma no formulário', async ({ page }) => {
|
||||
// Deve mostrar informações da turma ou ter turma pré-selecionada
|
||||
await expect(page.getByText(/turma|class/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve fazer upload para turma específica', async ({ page }) => {
|
||||
await page.getByLabelText(/título|title/i).fill('Material da Turma');
|
||||
|
||||
// const fileInput = page.getByLabelText(/arquivo/i);
|
||||
// await fileInput.setInputFiles('tests/fixtures/material.pdf');
|
||||
|
||||
// await page.getByRole('button', { name: /upload|salvar/i }).click();
|
||||
|
||||
// Deve redirecionar para detalhes da turma
|
||||
await expect(page).toHaveURL(/\/admin\/dashboard\/class/, { timeout: 10000 });
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Editar Arquivo', () => {
|
||||
test('deve carregar dados do arquivo', async ({ page }) => {
|
||||
// TODO: Usar ID de arquivo de teste
|
||||
await page.goto('/admin/dashboard/files/edit/file-id');
|
||||
|
||||
await expect(page.getByLabelText(/título|title/i)).not.toBeEmpty();
|
||||
});
|
||||
|
||||
test('deve permitir modificar título e descrição', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/files/edit/file-id');
|
||||
|
||||
await page.getByLabelText(/título|title/i).fill('Arquivo Editado');
|
||||
|
||||
const descField = page.getByLabelText(/descrição|description/i);
|
||||
if (await descField.isVisible()) {
|
||||
await descField.fill('Descrição atualizada');
|
||||
}
|
||||
|
||||
await page.getByRole('button', { name: /salvar|atualizar/i }).click();
|
||||
|
||||
await expect(page).toHaveURL(/\/admin\/dashboard\/files/, { timeout: 10000 });
|
||||
});
|
||||
|
||||
test('deve permitir trocar categoria', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/files/edit/file-id');
|
||||
|
||||
const categorySelect = page.getByRole('combobox', { name: /categoria/i });
|
||||
if (await categorySelect.isVisible()) {
|
||||
const originalValue = await categorySelect.inputValue();
|
||||
await categorySelect.selectOption({ index: 1 });
|
||||
|
||||
await page.getByRole('button', { name: /salvar|atualizar/i }).click();
|
||||
|
||||
// Verificar se mudou
|
||||
// await page.goto('/admin/dashboard/files/edit/file-id');
|
||||
// const newValue = await categorySelect.inputValue();
|
||||
// expect(newValue).not.toBe(originalValue);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Download de Arquivo', () => {
|
||||
test('deve ter botão de download', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/files');
|
||||
|
||||
const downloadButton = page.getByRole('link', { name: /download|baixar/i }).first();
|
||||
if (await downloadButton.isVisible()) {
|
||||
const downloadPromise = page.waitForEvent('download');
|
||||
|
||||
await downloadButton.click();
|
||||
|
||||
const download = await downloadPromise;
|
||||
expect(download.suggestedFilename()).toBeTruthy();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve abrir arquivo em nova aba', async ({ page }) => {
|
||||
const openButton = page.getByRole('link', { name: /abrir|open/i }).first();
|
||||
if (await openButton.isVisible()) {
|
||||
const newPagePromise = page.waitForEvent('popup');
|
||||
|
||||
await openButton.click();
|
||||
|
||||
const newPage = await newPagePromise;
|
||||
await expect(newPage).toHaveURL(/\.pdf|\.png|\.jpg/i);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Excluir Arquivo', () => {
|
||||
test('deve confirmar antes de excluir', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/files');
|
||||
|
||||
const deleteButton = page.getByRole('button', { name: /excluir|delete/i }).first();
|
||||
if (await deleteButton.isVisible()) {
|
||||
await deleteButton.click();
|
||||
|
||||
await expect(page.getByText(/tem certeza|deseja excluir/i)).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: /confirmar|sim/i })).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: /cancelar|não/i })).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve remover arquivo da lista após excluir', async ({ page }) => {
|
||||
// TODO: Implementar
|
||||
// await page.goto('/admin/dashboard/files');
|
||||
// const fileName = 'Arquivo Para Excluir';
|
||||
|
||||
// const initialCount = await page.getByText(fileName).count();
|
||||
|
||||
// await page.getByRole('button', { name: /excluir/i }).first().click();
|
||||
// await page.getByRole('button', { name: /confirmar/i }).click();
|
||||
|
||||
// await expect(page.getByText(fileName)).toHaveCount(initialCount - 1);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Upload Múltiplo', () => {
|
||||
test('deve aceitar múltiplos arquivos de uma vez', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/files/add');
|
||||
|
||||
// const fileInput = page.getByLabelText(/arquivo/i);
|
||||
// Se suportar múltiplos:
|
||||
// await fileInput.setInputFiles([
|
||||
// 'tests/fixtures/file1.pdf',
|
||||
// 'tests/fixtures/file2.pdf'
|
||||
// ]);
|
||||
|
||||
// await page.getByRole('button', { name: /upload|salvar/i }).click();
|
||||
|
||||
// Deve processar todos os arquivos
|
||||
});
|
||||
|
||||
test('deve mostrar barra de progresso durante upload', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/files/add');
|
||||
|
||||
// Após selecionar arquivo e iniciar upload
|
||||
// await expect(page.getByText(/enviando|uploading|progresso/i)).toBeVisible();
|
||||
// await expect(page.getByText(/concluído|sucesso/i)).toBeVisible({ timeout: 15000 });
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Validações de Upload', () => {
|
||||
test('deve rejeitar arquivo muito grande', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/files/add');
|
||||
|
||||
// Criar arquivo temporário grande
|
||||
// const largeFile = Buffer.alloc(20 * 1024 * 1024); // 20MB
|
||||
// await page.getByLabelText(/arquivo/i).setInputFiles({
|
||||
// name: 'large.pdf',
|
||||
// mimeType: 'application/pdf',
|
||||
// buffer: largeFile
|
||||
// });
|
||||
|
||||
await page.getByRole('button', { name: /upload|salvar/i }).click();
|
||||
|
||||
await expect(page.getByText(/arquivo muito grande|tamanho máximo/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve rejeitar formato não suportado', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/files/add');
|
||||
|
||||
// await page.getByLabelText(/arquivo/i).setInputFiles('tests/fixtures/file.exe');
|
||||
|
||||
await page.getByRole('button', { name: /upload|salvar/i }).click();
|
||||
|
||||
await expect(page.getByText(/formato não suportado|tipo inválido/i)).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Preview de Arquivo', () => {
|
||||
test('deve mostrar preview de imagem', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/files/edit/image-file-id');
|
||||
|
||||
const preview = page.locator('img[src*="/uploads/"]').first();
|
||||
if (await preview.isVisible()) {
|
||||
await expect(preview).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve mostrar ícone para PDF', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/files/edit/pdf-file-id');
|
||||
|
||||
const pdfIcon = page.locator('[class*="pdf"]').first();
|
||||
if (await pdfIcon.isVisible()) {
|
||||
await expect(pdfIcon).toBeVisible();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,168 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('Admin - Pagamentos', () => {
|
||||
// TODO: Fazer login como admin antes de cada teste
|
||||
// test.beforeEach(async ({ page }) => {
|
||||
// await page.goto('/auth/login');
|
||||
// await page.getByLabel(/email/i).fill('[email protected]');
|
||||
// await page.getByLabel(/senha/i).fill('123456');
|
||||
// await page.getByRole('button', { name: /entrar/i }).click();
|
||||
// await page.waitForURL(/\/admin\/dashboard/);
|
||||
// });
|
||||
|
||||
test.describe('Lista de Pagamentos', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/payments');
|
||||
});
|
||||
|
||||
test('deve mostrar lista de pagamentos', async ({ page }) => {
|
||||
await expect(page.getByText(/pagamentos|payments/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve ter link para visualização por turma', async ({ page }) => {
|
||||
await expect(page.getByRole('link', { name: /por turma|by class/i })).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve mostrar colunas principais', async ({ page }) => {
|
||||
await expect(page.getByText(/aluno/i)).toBeVisible();
|
||||
await expect(page.getByText(/valor|amount/i)).toBeVisible();
|
||||
await expect(page.getByText(/status/i)).toBeVisible();
|
||||
await expect(page.getByText(/vencimento|due date/i)).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Pagamentos por Turma', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/payments/by-class');
|
||||
});
|
||||
|
||||
test('deve mostrar cards de turmas', async ({ page }) => {
|
||||
await expect(page.getByText(/turmas|classes/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve expandir turma ao clicar', async ({ page }) => {
|
||||
const firstClassCard = page.locator('.bg-white, .dark\\:bg-neutral-800').first();
|
||||
await firstClassCard.click();
|
||||
|
||||
// Deve mostrar tabela de pagamentos dentro
|
||||
await expect(page.locator('table')).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve mostrar filtros de status', async ({ page }) => {
|
||||
const statusFilter = page.getByRole('combobox');
|
||||
if (await statusFilter.isVisible()) {
|
||||
await statusFilter.selectOption('pending');
|
||||
await page.waitForTimeout(500);
|
||||
// Verificar se filtrou
|
||||
}
|
||||
});
|
||||
|
||||
test('deve ter botões expandir/recolher todos', async ({ page }) => {
|
||||
await expect(page.getByRole('button', { name: /expandir/i })).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: /recolher/i })).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve mostrar estatísticas', async ({ page }) => {
|
||||
await expect(page.getByText(/pendentes/i)).toBeVisible();
|
||||
await expect(page.getByText(/aguardando verificação/i)).toBeVisible();
|
||||
await expect(page.getByText(/pagos/i)).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Aprovação de Pagamento', () => {
|
||||
test('deve mostrar botões de aprovar/rejeitar para pagamentos pendentes', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/payments/by-class');
|
||||
|
||||
// Expandir primeira turma
|
||||
const firstClassCard = page.locator('.bg-white, .dark\\:bg-neutral-800').first();
|
||||
await firstClassCard.click();
|
||||
|
||||
// Procurar botões de ação
|
||||
const approveButton = page.getByRole('button').filter({ hasText: /aprovar|check/i }).first();
|
||||
const rejectButton = page.getByRole('button').filter({ hasText: /rejeitar|x/i }).first();
|
||||
|
||||
// Podem não existir pagamentos pendentes
|
||||
// if (await approveButton.isVisible()) {
|
||||
// await expect(rejectButton).toBeVisible();
|
||||
// }
|
||||
});
|
||||
|
||||
test('deve abrir modal de rejeição ao clicar em rejeitar', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/payments/by-class');
|
||||
|
||||
// Expandir e procurar pagamento para rejeitar
|
||||
const firstClassCard = page.locator('.bg-white, .dark\\:bg-neutral-800').first();
|
||||
await firstClassCard.click();
|
||||
|
||||
const rejectButton = page.getByRole('button').filter({ hasText: /rejeitar|x/i }).first();
|
||||
if (await rejectButton.isVisible()) {
|
||||
await rejectButton.click();
|
||||
|
||||
// Deve abrir modal
|
||||
await expect(page.getByText(/motivo da rejeição/i)).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: /confirmar/i })).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: /cancelar/i })).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve ver comprovante', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/payments/by-class');
|
||||
|
||||
// Procurar botão de ver comprovante
|
||||
const viewReceiptButton = page.getByRole('button').filter({ hasText: /ver|olho/i }).first();
|
||||
if (await viewReceiptButton.isVisible()) {
|
||||
await viewReceiptButton.click();
|
||||
|
||||
// Deve abrir modal
|
||||
await expect(page.locator('.fixed.inset-0')).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: /fechar|✕/i })).toBeVisible();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Labels/Badges de Status', () => {
|
||||
test('deve mostrar badge correto para cada status', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/payments/by-class');
|
||||
|
||||
// Status possíveis: pending_verification, verified, rejected, pending
|
||||
const statuses = [/aguardando/i, /pago|verificado/i, /rejeitado/i, /pendente/i];
|
||||
|
||||
for (const status of statuses) {
|
||||
const badge = page.getByText(status).first();
|
||||
if (await badge.isVisible()) {
|
||||
// Badge deve ter classes de cor
|
||||
await expect(badge).toBeVisible();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Hover Cards', () => {
|
||||
test('deve ter hover suave nos cards de turma', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/payments/by-class');
|
||||
|
||||
const firstClassCard = page.locator('.bg-white, .dark\\:bg-neutral-800').first();
|
||||
|
||||
// Hover não deve mudar drasticamente
|
||||
await firstClassCard.hover();
|
||||
await page.waitForTimeout(100);
|
||||
|
||||
// Verificar se card ainda visível e funcional
|
||||
await expect(firstClassCard).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve ter hover suave nas linhas da tabela', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/payments/by-class');
|
||||
|
||||
const firstClassCard = page.locator('.bg-white, .dark\\:bg-neutral-800').first();
|
||||
await firstClassCard.click();
|
||||
|
||||
const tableRow = page.locator('tr').nth(1); // Pular header
|
||||
if (await tableRow.isVisible()) {
|
||||
await tableRow.hover();
|
||||
await page.waitForTimeout(100);
|
||||
await expect(tableRow).toBeVisible();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,304 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('Admin - Estatísticas de Provas', () => {
|
||||
// TODO: Fazer login como admin
|
||||
// test.beforeEach(async ({ page }) => {
|
||||
// await page.goto('/auth/login');
|
||||
// await page.getByLabel(/email/i).fill('[email protected]');
|
||||
// await page.getByLabel(/senha/i).fill('123456');
|
||||
// await page.getByRole('button', { name: /entrar/i }).click();
|
||||
// await page.waitForURL(/\/dispatcher/);
|
||||
// await page.getByRole('button', { name: /admin/i }).click();
|
||||
// });
|
||||
|
||||
test.describe('Página de Estatísticas', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/statistics/exams');
|
||||
});
|
||||
|
||||
test('deve mostrar header com PageHeader', async ({ page }) => {
|
||||
await expect(page.getByText(/estatísticas de provas/i)).toBeVisible();
|
||||
await expect(page.getByText(/visualize estatísticas/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve ter filtro de período', async ({ page }) => {
|
||||
await expect(page.getByRole('combobox', { name: /período/i })).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve ter botão de atualizar', async ({ page }) => {
|
||||
const refreshButton = page.getByRole('button', { name: /atualizar|refresh/i });
|
||||
if (await refreshButton.isVisible()) {
|
||||
await expect(refreshButton).toBeVisible();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Estatísticas Agregadas', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/statistics/exams');
|
||||
});
|
||||
|
||||
test('deve mostrar total de tentativas', async ({ page }) => {
|
||||
await expect(page.getByText(/total de tentativas/i)).toBeVisible();
|
||||
const totalValue = page.locator('text=/deve-total/').first(); // Ajustar seletor
|
||||
if (await totalValue.isVisible()) {
|
||||
const text = await totalValue.textContent();
|
||||
expect(text).toMatch(/\d+/);
|
||||
}
|
||||
});
|
||||
|
||||
test('deve mostrar média de notas', async ({ page }) => {
|
||||
await expect(page.getByText(/média de notas/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve mostrar média de aproveitamento', async ({ page }) => {
|
||||
await expect(page.getByText(/média de aproveitamento/i)).toBeVisible();
|
||||
const percentageValue = page.locator('text=/deve-percent/').first();
|
||||
if (await percentageValue.isVisible()) {
|
||||
const text = await percentageValue.textContent();
|
||||
expect(text).toMatch(/\d+%/);
|
||||
}
|
||||
});
|
||||
|
||||
test('deve mostrar taxa de aprovação', async ({ page }) => {
|
||||
await expect(page.getByText(/taxa de aprovação/i)).toBeVisible();
|
||||
const passRateValue = page.locator('text=/deve-pass/').first();
|
||||
if (await passRateValue.isVisible()) {
|
||||
const text = await passRateValue.textContent();
|
||||
expect(text).toMatch(/\d+%/);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Estatísticas por Turma', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/statistics/exams');
|
||||
});
|
||||
|
||||
test('deve mostrar cards de turmas', async ({ page }) => {
|
||||
await expect(page.getByText(/por turma|by class/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve mostrar nome da turma', async ({ page }) => {
|
||||
const classCard = page.locator('[data-testid="class-stat-card"]').first();
|
||||
if (await classCard.isVisible()) {
|
||||
await expect(classCard.getByText(/turma|class/i)).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve mostrar número de tentativas por turma', async ({ page }) => {
|
||||
const classCard = page.locator('[data-testid="class-stat-card"]').first();
|
||||
if (await classCard.isVisible()) {
|
||||
await expect(classCard.getByText(/tentativas/i)).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve mostrar média da turma com cor baseada no desempenho', async ({ page }) => {
|
||||
const classCard = page.locator('[data-testid="class-stat-card"]').first();
|
||||
if (await classCard.isVisible()) {
|
||||
const avgLabel = classCard.locator('[data-testid="average-label"]').first();
|
||||
if (await avgLabel.isVisible()) {
|
||||
// Deve ter cor: emerald (bom), amber (médio), red (ruim)
|
||||
const classes = await avgLabel.getAttribute('class') || '';
|
||||
expect(classes).toMatch(/label-emerald|label-amber|label-red|bg-emerald|bg-amber|bg-red/i);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Estatísticas por Template', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/statistics/exams');
|
||||
});
|
||||
|
||||
test('deve mostrar cards de templates', async ({ page }) => {
|
||||
await expect(page.getByText(/por modelo|por template|by template/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve mostrar título do template', async ({ page }) => {
|
||||
const templateCard = page.locator('[data-testid="template-stat-card"]').first();
|
||||
if (await templateCard.isVisible()) {
|
||||
await expect(templateCard.getByText(/prova|template/i)).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve mostrar número de tentativas por template', async ({ page }) => {
|
||||
const templateCard = page.locator('[data-testid="template-stat-card"]').first();
|
||||
if (await templateCard.isVisible()) {
|
||||
await expect(templateCard.getByText(/tentativas/i)).toBeVisible();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Lista de Tentativas', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/statistics/exams');
|
||||
});
|
||||
|
||||
test('deve mostrar tabela de tentativas', async ({ page }) => {
|
||||
await expect(page.getByText(/tentativas de prova/i)).toBeVisible();
|
||||
await expect(page.locator('table')).toBeVisible();
|
||||
});
|
||||
|
||||
test('deve mostrar colunas principais', async ({ page }) => {
|
||||
const table = page.locator('table').first();
|
||||
if (await table.isVisible()) {
|
||||
await expect(table.getByText(/aluno|student/i)).toBeVisible();
|
||||
await expect(table.getByText(/turma|class/i)).toBeVisible();
|
||||
await expect(table.getByText(/modelo|template/i)).toBeVisible();
|
||||
await expect(table.getByText(/nota|score/i)).toBeVisible();
|
||||
await expect(table.getByText(/status/i)).toBeVisible();
|
||||
await expect(table.getByText(/data/i)).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve mostrar badge de status correção', async ({ page }) => {
|
||||
const table = page.locator('table').first();
|
||||
if (await table.isVisible()) {
|
||||
const statusCell = table.locator('td').last();
|
||||
if (await statusCell.isVisible()) {
|
||||
// Status: fully_graded, partially_graded, auto_graded, pending
|
||||
await expect(statusCell.locator('[data-testid="label"]')).toBeVisible();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Paginação', () => {
|
||||
test('deve ter controles de paginação', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/statistics/exams');
|
||||
|
||||
const pagination = page.locator('[data-testid="pagination"]');
|
||||
if (await pagination.isVisible()) {
|
||||
await expect(pagination.getByRole('button', { name: /anterior|previous/i })).toBeVisible();
|
||||
await expect(pagination.getByRole('button', { name: /próxima|next/i })).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve mostrar página atual', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/statistics/exams');
|
||||
|
||||
const pageInfo = page.getByText(/página \d+ de \d+/i);
|
||||
if (await pageInfo.isVisible()) {
|
||||
await expect(pageInfo).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('deve navegar entre páginas', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/statistics/exams');
|
||||
|
||||
const nextButton = page.getByRole('button', { name: /próxima|next/i });
|
||||
if (await nextButton.isEnabled()) {
|
||||
await nextButton.click();
|
||||
|
||||
// Deve mudar a página
|
||||
const pageInfo = page.getByText(/página \d+ de \d+/i);
|
||||
if (await pageInfo.isVisible()) {
|
||||
const text = await pageInfo.textContent();
|
||||
expect(text).toMatch(/página [2-9]/);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Filtros', () => {
|
||||
test('deve filtrar por status', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/statistics/exams');
|
||||
|
||||
const statusFilter = page.getByRole('combobox', { name: /status/i });
|
||||
if (await statusFilter.isVisible()) {
|
||||
await statusFilter.selectOption('paid');
|
||||
|
||||
// Deve recarregar resultados
|
||||
await page.waitForTimeout(500);
|
||||
// Verificar se filtrou
|
||||
}
|
||||
});
|
||||
|
||||
test('deve filtrar por turma', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/statistics/exams');
|
||||
|
||||
const classFilter = page.getByRole('combobox', { name: /turma/i });
|
||||
if (await classFilter.isVisible()) {
|
||||
const initialCount = await page.locator('table tbody tr').count();
|
||||
|
||||
await classFilter.selectOption({ index: 0 });
|
||||
|
||||
await page.waitForTimeout(500);
|
||||
// Pode mostrar menos resultados
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Labels/Badges de Status', () => {
|
||||
test('deve usar Label component corretamente', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/statistics/exams');
|
||||
|
||||
const label = page.locator('[data-testid="label"]').first();
|
||||
if (await label.isVisible()) {
|
||||
// Deve ter as classes de cor
|
||||
const classes = await label.getAttribute('class') || '';
|
||||
expect(classes).toMatch(/label-(emerald|amber|red|blue|gray|sky|indigo|purple)/);
|
||||
}
|
||||
});
|
||||
|
||||
test('deve mostrar cor correta para cada status', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/statistics/exams');
|
||||
|
||||
// Verificar cores dos badges de porcentagem
|
||||
const percentageLabels = page.locator('[data-testid="average-percent-label"]');
|
||||
const count = await percentageLabels.count();
|
||||
|
||||
for (let i = 0; i < Math.min(count, 3); i++) {
|
||||
const label = percentageLabels.nth(i);
|
||||
const classes = await label.getAttribute('class') || '';
|
||||
// >= 70%: emerald, >= 60%: amber, < 60%: red
|
||||
expect(classes).toMatch(/label-(emerald|amber|red)/);
|
||||
}
|
||||
});
|
||||
|
||||
test('deve mostrar cor correta para status de correção', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/statistics/exams');
|
||||
|
||||
const gradingLabels = page.locator('[data-testid="grading-status-label"]');
|
||||
const count = await gradingLabels.count();
|
||||
|
||||
for (let i = 0; i < Math.min(count, 3); i++) {
|
||||
const label = gradingLabels.nth(i);
|
||||
const classes = await label.getAttribute('class') || '';
|
||||
// fully_graded: emerald, partially_graded: amber, auto_graded: blue, pending: gray
|
||||
expect(classes).toMatch(/label-(emerald|amber|blue|gray)/);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Exportação de Dados', () => {
|
||||
test('deve ter botão de exportar CSV', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/statistics/exams');
|
||||
|
||||
const exportButton = page.getByRole('button', { name: /exportar|csv/i });
|
||||
if (await exportButton.isVisible()) {
|
||||
const downloadPromise = page.waitForEvent('download');
|
||||
|
||||
await exportButton.click();
|
||||
|
||||
const download = await downloadPromise;
|
||||
expect(download.suggestedFilename()).toMatch(/\.csv$/);
|
||||
}
|
||||
});
|
||||
|
||||
test('deve ter botão de exportar PDF', async ({ page }) => {
|
||||
await page.goto('/admin/dashboard/statistics/exams');
|
||||
|
||||
const exportButton = page.getByRole('button', { name: /pdf/i });
|
||||
if (await exportButton.isVisible()) {
|
||||
const downloadPromise = page.waitForEvent('download');
|
||||
|
||||
await exportButton.click();
|
||||
|
||||
const download = await downloadPromise;
|
||||
expect(download.suggestedFilename()).toMatch(/\.pdf$/);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user