@devix-tecnologia/directus-extension-inframe
Version:
DEPRECATED: Use 'directus-extension-inframe' instead. This package is no longer maintained.
244 lines (187 loc) • 9.69 kB
text/typescript
import { test, expect, Browser, BrowserContext, Page } from '@playwright/test';
import fs from 'fs';
import path from 'path';
/**
* Credenciais de admin padrão do ambiente de teste
*/
const ADMIN_EMAIL = 'admin@example.com';
const ADMIN_PASSWORD = 'admin123';
// Para CommonJS, usamos __dirname diretamente
const storageFile = path.resolve(__dirname, 'auth-storage.json');
// Variáveis compartilhadas entre os testes
let sharedContext: BrowserContext;
let sharedPage: Page;
// Rodar os testes em série para evitar conflitos de sessão
test.describe.configure({ mode: 'serial' });
test.describe('Directus Admin Panel - Login e Coleções', () => {
test.beforeAll(async ({ browser }: { browser: Browser }) => {
// Criar contexto e página compartilhados
sharedContext = await browser.newContext();
sharedPage = await sharedContext.newPage();
// Navega para o login e faz autenticação
await sharedPage.goto('/admin/login', { waitUntil: 'networkidle' });
// Aguardar um pouco para a página carregar completamente
await sharedPage.waitForTimeout(1000);
// Verificar se há um botão "Continue" (sessão existente)
// O Directus mostra esse botão quando já existe uma sessão autenticada
const continueButton = sharedPage.locator('button:has-text("Continue")');
const hasContinueButton = await continueButton.isVisible({ timeout: 3000 }).catch(() => false);
if (hasContinueButton) {
// Se há botão Continue, clicar nele e aguardar redirecionamento
await continueButton.click();
await sharedPage.waitForURL('**/admin/**', { timeout: 20000 });
// Aguardar a página carregar completamente após o Continue
await sharedPage.waitForLoadState('networkidle');
await sharedPage.waitForTimeout(2000);
} else {
// Caso contrário, fazer login normal
await sharedPage.fill('input[type="email"]', ADMIN_EMAIL);
await sharedPage.fill('input[type="password"]', ADMIN_PASSWORD);
await sharedPage.click('button[type="submit"]');
await sharedPage.waitForURL('**/admin/**', { timeout: 20000 });
await sharedPage.waitForLoadState('networkidle');
}
// Esperar elementos de navegação visíveis (com timeout maior)
await sharedPage.waitForSelector('#navigation, aside[role="navigation"], [data-test-id="navigation"]', {
timeout: 30000,
});
});
test.afterAll(async () => {
// Fechar contexto compartilhado
if (sharedContext) {
await sharedContext.close();
}
// Remover storage file (se existir)
if (fs.existsSync(storageFile)) {
try {
fs.unlinkSync(storageFile);
} catch {
// ignore
}
}
});
test('deve fazer login com sucesso e estabilizar o dashboard', async () => {
// A página compartilhada já está autenticada e no dashboard
// Apenas verificar que os elementos estão presentes
// Verificar URL e elementos do dashboard
expect(sharedPage.url()).toContain('/admin');
// Aguardar navegação estar visível (já deve estar do beforeAll)
const nav = await sharedPage.locator('#navigation, aside[role="navigation"], [data-test-id="navigation"]').first();
await expect(nav).toBeVisible({ timeout: 5000 });
// Tirar screenshot para debug
await sharedPage.screenshot({ path: 'tests/e2e/screenshots/dashboard.png', fullPage: true });
});
test('deve acessar a listagem de coleções (Content)', async () => {
// No Directus 11, não há uma página /admin/content genérica
// Vamos verificar se conseguimos acessar uma coleção específica
await sharedPage.goto('/admin/content/inframe', { waitUntil: 'networkidle' });
// Se o Directus redirecionar para login, falhar explicitamente
if (sharedPage.url().includes('/login')) {
throw new Error('Redirecionado para login — sessão inválida');
}
// Aguardar elementos da página de coleção (header, tabela, ou empty state)
await sharedPage.waitForSelector('header, .header-bar, table, [role="table"], .v-info, .empty-state', {
timeout: 20000,
});
// Screenshot para debug
await sharedPage.screenshot({ path: 'tests/e2e/screenshots/collections-page.png', fullPage: true });
});
test('deve verificar que a coleção "inframe" existe e está acessível', async () => {
// Usar página compartilhada
await sharedPage.goto('/admin/content/inframe', { waitUntil: 'networkidle' });
if (sharedPage.url().includes('/login')) {
throw new Error('Redirecionado para login — sessão inválida');
}
// Aguardar elementos que indicam página carregada
await sharedPage.waitForSelector(
'table, [role="table"], .v-grid, .grid-container, .v-info, .empty-state, .v-notice, header',
{ timeout: 20000 },
);
// Fazer uma verificação leve no corpo para erros óbvios
const bodyText = (await sharedPage.textContent('body')) || '';
expect(bodyText.toLowerCase()).not.toContain('forbidden');
expect(bodyText.toLowerCase()).not.toContain('no permission');
await sharedPage.screenshot({ path: 'tests/e2e/screenshots/inframe-collection.png', fullPage: true });
});
test('deve listar as coleções customizadas criadas pelo hook', async () => {
// Usar página compartilhada
await sharedPage.goto('/admin', { waitUntil: 'networkidle' });
// Verificar se há botão Continue novamente (pode aparecer ao navegar)
const continueButton = sharedPage.locator('button:has-text("Continue")');
const hasContinueButton = await continueButton.isVisible({ timeout: 3000 }).catch(() => false);
if (hasContinueButton) {
await continueButton.click();
await sharedPage.waitForLoadState('networkidle');
await sharedPage.waitForTimeout(2000);
}
// Aguardar navegação
const nav = await sharedPage.waitForSelector('#navigation, aside[role="navigation"], [data-test-id="navigation"]', {
timeout: 20000,
});
const navText = (await nav.textContent()) || '';
const hasInframe = navText.toLowerCase().includes('inframe') || navText.toLowerCase().includes('relatórios');
const hasLanguages = navText.toLowerCase().includes('language') || navText.toLowerCase().includes('idioma');
// Screenshot da navegação
await sharedPage.screenshot({ path: 'tests/e2e/screenshots/navigation.png', fullPage: false });
// Não falhar imediatamente — apenas informar caso não encontre (pode ser permissões)
if (!hasInframe && !hasLanguages) {
throw new Error('Coleções customizadas não encontradas na navegação. Verifique permissões.');
}
});
test('deve criar um novo registro na coleção inframe', async () => {
// Navegar para a coleção inframe
await sharedPage.goto('/admin/content/inframe', { waitUntil: 'networkidle' });
// Aguardar a página carregar
await sharedPage.waitForTimeout(2000);
// Screenshot para debug
await sharedPage.screenshot({ path: 'tests/e2e/screenshots/inframe-collection-page.png', fullPage: true });
// No Directus 11, o botão de criar é um link <a> com classe button
// Usar o link que contém o texto "Create Item" ou o ícone add
const createButton = await sharedPage.waitForSelector(
'a[href*="/inframe/+"]:has-text("Create Item"), a.button.icon[href*="/inframe/+"]',
{ timeout: 10000 },
);
await createButton.click();
// Aguardar o formulário de criação abrir
await sharedPage.waitForURL('**/admin/content/inframe/+');
// Aguardar o formulário carregar completamente
await sharedPage.waitForSelector('main', { state: 'visible' });
await sharedPage.waitForTimeout(2000);
// Verificar se ainda estamos na página de criação
expect(sharedPage.url()).toContain('/inframe/+');
// Status já vem preenchido com "Rascunho", deixar como está
// Ícone é opcional, vamos pular para evitar o dropdown
// Preencher o campo URL diretamente (terceiro input de texto)
// Usar waitForSelector para garantir que o campo existe
await sharedPage.waitForSelector('main input[type="text"]', { state: 'visible', timeout: 5000 });
const urlField = await sharedPage.locator('main input[type="text"]').nth(2); // terceiro input (índice 2)
await urlField.click(); // Focar no campo
await urlField.fill('https://example.com/test-report');
await sharedPage.waitForTimeout(500);
// Screenshot antes de salvar
await sharedPage.screenshot({ path: 'tests/e2e/screenshots/create-inframe-form.png', fullPage: true });
// Clicar no botão de salvar (ícone check no banner/header)
const saveButton = await sharedPage.waitForSelector(
'banner button:has-text("check"), button:has([data-icon="check"])',
{
timeout: 5000,
},
);
await saveButton.click();
// Aguardar o salvamento e redirecionamento
await sharedPage.waitForTimeout(3000);
// Verificar se foi redirecionado para a listagem ou para o item criado
const currentUrl = sharedPage.url();
expect(currentUrl).toMatch(/\/admin\/content\/inframe/);
// Screenshot após salvar
await sharedPage.screenshot({ path: 'tests/e2e/screenshots/after-create-inframe.png', fullPage: true });
// Verificar se o item aparece na listagem
await sharedPage.goto('/admin/content/inframe', { waitUntil: 'networkidle' });
await sharedPage.waitForTimeout(2000);
// Procurar pela URL que acabamos de criar
const itemCreated = await sharedPage.locator('text=https://example.com/test-report').first().isVisible({
timeout: 5000,
});
expect(itemCreated).toBeTruthy();
});
});