329 lines
13 KiB
JavaScript
329 lines
13 KiB
JavaScript
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();
|
|
});
|
|
});
|
|
});
|