Files
pn-new-crm/tests/e2e/smoke/16-document-templates.spec.ts

163 lines
6.2 KiB
TypeScript
Raw Normal View History

import { test, expect } from '@playwright/test';
import { login, navigateTo, PORT_SLUG } from './helpers';
test.describe('Document Templates', () => {
test.beforeEach(async ({ page }) => {
await login(page, 'super_admin');
});
// Test 29: Navigate to document templates
test('document templates page loads', async ({ page }) => {
await navigateTo(page, '/admin/templates');
await page.waitForTimeout(2_000);
const heading = page.getByText(/template/i).first();
await expect(heading).toBeVisible({ timeout: 10_000 });
});
// Test 30: Create a new template
test('create a new document template', async ({ page }) => {
await navigateTo(page, '/admin/templates');
await page.waitForTimeout(2_000);
const createBtn = page.getByRole('button', { name: /create|add|new/i }).first();
await expect(createBtn).toBeVisible({ timeout: 5_000 });
await createBtn.click();
await page.waitForTimeout(1_000);
const dialog = page.locator('[role="dialog"], [data-state="open"]').first();
await expect(dialog).toBeVisible({ timeout: 3_000 });
// Fill name
const nameInput = dialog.locator('input').first();
await nameInput.fill('Test EOI Template');
// Select type
const typeSelect = dialog.locator('select, [role="combobox"]').first();
if (await typeSelect.isVisible({ timeout: 2_000 }).catch(() => false)) {
await typeSelect.click();
await page.waitForTimeout(300);
const eoiOption = page.getByRole('option', { name: /eoi/i }).first();
if (await eoiOption.isVisible({ timeout: 2_000 }).catch(() => false)) {
await eoiOption.click();
}
}
// The template editor could be TipTap or a JSON textarea
const contentArea = dialog.locator('textarea, [contenteditable="true"], .ProseMirror').first();
await expect(contentArea).toBeVisible({ timeout: 5_000 });
});
// Test 31: Template with variable placeholder
test('template saves with variable placeholders', async ({ page }) => {
await navigateTo(page, '/admin/templates');
await page.waitForTimeout(2_000);
const createBtn = page.getByRole('button', { name: /create|add|new/i }).first();
if (await createBtn.isVisible({ timeout: 3_000 }).catch(() => false)) {
await createBtn.click();
await page.waitForTimeout(1_000);
const dialog = page.locator('[role="dialog"], [data-state="open"]').first();
// Fill name
const nameInput = dialog.locator('input').first();
await nameInput.fill('Variable Test Template');
// Type content with variable
const contentArea = dialog.locator('textarea, [contenteditable="true"]').first();
if (await contentArea.isVisible({ timeout: 3_000 }).catch(() => false)) {
// For textarea: paste TipTap JSON with variables
const tiptapJson = JSON.stringify({
type: 'doc',
content: [
{
type: 'heading',
attrs: { level: 1 },
content: [{ type: 'text', text: 'Expression of Interest' }],
},
{
type: 'paragraph',
content: [{ type: 'text', text: 'Dear {{client.name}},' }],
},
{
type: 'paragraph',
content: [
{ type: 'text', text: 'This letter confirms your interest in berth ' },
{ type: 'text', text: '{{berth.mooring_number}}' },
{ type: 'text', text: ' at ' },
{ type: 'text', text: '{{port.name}}' },
{ type: 'text', text: '.' },
],
},
],
});
await contentArea.fill(tiptapJson);
}
// Save
const saveBtn = dialog.getByRole('button', { name: /save|create|submit/i }).first();
if (await saveBtn.isVisible({ timeout: 2_000 }).catch(() => false)) {
await saveBtn.click();
await page.waitForTimeout(3_000);
}
}
expect(true).toBeTruthy();
});
// Test 32: Preview template renders PDF
test('template preview generates PDF', async ({ page }) => {
await navigateTo(page, '/admin/templates');
await page.waitForTimeout(2_000);
// Find a preview button on an existing template
const previewBtn = page.getByRole('button', { name: /preview/i }).first();
if (await previewBtn.isVisible({ timeout: 5_000 }).catch(() => false)) {
await previewBtn.click();
await page.waitForTimeout(3_000);
// Should show a preview dialog with PDF content (iframe or embedded)
const previewDialog = page.locator('[role="dialog"]').last();
const hasPreview = await previewDialog.isVisible({ timeout: 5_000 }).catch(() => false);
expect(hasPreview).toBeTruthy();
}
});
// Test 33: Edit template creates new version
test('editing template creates version history', async ({ page }) => {
await navigateTo(page, '/admin/templates');
await page.waitForTimeout(2_000);
// Click edit on first template
const editBtn = page.getByRole('button', { name: /edit/i }).first();
if (await editBtn.isVisible({ timeout: 5_000 }).catch(() => false)) {
await editBtn.click();
await page.waitForTimeout(1_000);
// Modify and save
const dialog = page.locator('[role="dialog"], [data-state="open"]').first();
const nameInput = dialog.locator('input').first();
const currentName = await nameInput.inputValue();
await nameInput.fill(currentName + ' (edited)');
const saveBtn = dialog.getByRole('button', { name: /save|update/i }).first();
if (await saveBtn.isVisible({ timeout: 2_000 }).catch(() => false)) {
await saveBtn.click();
await page.waitForTimeout(3_000);
}
}
// Look for version history button
const historyBtn = page.getByRole('button', { name: /history|version/i }).first();
if (await historyBtn.isVisible({ timeout: 5_000 }).catch(() => false)) {
await historyBtn.click();
await page.waitForTimeout(1_000);
// Should show version entries
const versionList = page.locator('[role="dialog"]').last();
const hasVersions = await versionList.getByText(/version|v\d/i).isVisible({ timeout: 3_000 }).catch(() => false);
expect(hasVersions).toBeTruthy();
}
});
});