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('admin@teste.com'); // 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('teacher@teste.com'); // 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(); }); }); });