176 lines
6.7 KiB
JavaScript
176 lines
6.7 KiB
JavaScript
import { test, expect } from '@playwright/test';
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { adminPath, apiList, apiPost, ensureDataSource, ensureMailshot, cleanupByNames } from './helpers.mjs';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
const renewalsTemplate = fs.readFileSync(path.resolve(__dirname, '../../../formats/renewals_v4.html'), 'utf8');
|
|
|
|
const dsName = process.env.E2E_RENEWAL_DATASOURCE || 'renewal_accounts_with_contacts';
|
|
const mailshotPurpose = process.env.E2E_RENEWAL_MAILSHOT_PURPOSE || 'Renewals (pending accounts and contacts)';
|
|
const allowCreate = process.env.E2E_RENEWAL_ALLOW_CREATE === '1';
|
|
const runEnabled = process.env.E2E_RENEWAL_ENABLE === '1';
|
|
|
|
test.describe('renewal dataset: download pdf e2e', () => {
|
|
test.skip(!runEnabled, 'Enable with E2E_RENEWAL_ENABLE=1');
|
|
|
|
const clickAndExpectDownload = async (page, buttonName, expectedFilenamePart) => {
|
|
page.once('dialog', async (dialog) => {
|
|
await dialog.accept();
|
|
});
|
|
|
|
const nextMatchingDownload = async () => {
|
|
const deadline = Date.now() + 240000;
|
|
while (Date.now() < deadline) {
|
|
const remaining = Math.max(1, deadline - Date.now());
|
|
const download = await page.waitForEvent('download', { timeout: remaining }).catch(() => null);
|
|
if (!download) {
|
|
break;
|
|
}
|
|
if (download.suggestedFilename().includes(expectedFilenamePart)) {
|
|
return download;
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
|
|
const downloadPromise = nextMatchingDownload();
|
|
await page.getByRole('button', { name: buttonName }).click();
|
|
|
|
let downloaded;
|
|
try {
|
|
downloaded = await downloadPromise;
|
|
} catch {
|
|
const critical = page.getByText('There has been a critical error on this website.');
|
|
if (await critical.count()) {
|
|
throw new Error(`Download action "${buttonName}" reached a WordPress critical error page.`);
|
|
}
|
|
const failBanner = page.locator('strong', { hasText: 'PDF generation failed.' });
|
|
if (await failBanner.count()) {
|
|
const msg = (await page.locator('.wrap').innerText()).replace(/\s+/g, ' ').trim();
|
|
throw new Error(`Download action "${buttonName}" failed in UI: ${msg}`);
|
|
}
|
|
throw new Error(`Download action "${buttonName}" timed out waiting for file download.`);
|
|
}
|
|
if (!downloaded) {
|
|
throw new Error(`Download action "${buttonName}" did not produce expected file "${expectedFilenamePart}".`);
|
|
}
|
|
|
|
expect(downloaded.suggestedFilename()).toContain(expectedFilenamePart);
|
|
const outPath = await downloaded.path();
|
|
expect(outPath).toBeTruthy();
|
|
const outSize = fs.statSync(outPath).size;
|
|
expect(outSize).toBeGreaterThan(1000);
|
|
};
|
|
|
|
const resolveMailshot = async (request) => {
|
|
const uniq = `${Date.now()}_${Math.floor(Math.random() * 100000)}`;
|
|
const purpose = `e2e_renewal_download_${uniq}`;
|
|
const dsCreatedName = `e2e_renewal_ds_${uniq}`;
|
|
|
|
let mailshotId = '';
|
|
let effectiveDsName = dsName;
|
|
let createdMailshot = false;
|
|
const mailshotList = await apiList(request, 'feca_mailshots_mailshots_api');
|
|
expect(mailshotList.ok).toBeTruthy();
|
|
const existing = (mailshotList.items || []).find(
|
|
(row) => String(row.Purpose || '') === mailshotPurpose
|
|
);
|
|
|
|
if (existing) {
|
|
mailshotId = String(existing.id || '');
|
|
effectiveDsName = String(existing.DataSource || '').trim();
|
|
if (effectiveDsName === '') {
|
|
throw new Error(`Mailshot "${mailshotPurpose}" has no DataSource.`);
|
|
}
|
|
} else {
|
|
const dsList = await apiList(request, 'feca_mailshots_data_sources_api');
|
|
expect(dsList.ok).toBeTruthy();
|
|
const dsExists = (dsList.items || []).some((row) => String(row.name || '') === dsName);
|
|
if (!dsExists) {
|
|
if (!allowCreate) {
|
|
throw new Error(`Required data source not found: ${dsName}`);
|
|
}
|
|
await ensureDataSource(request, dsCreatedName, dsName);
|
|
effectiveDsName = dsCreatedName;
|
|
}
|
|
if (!allowCreate) {
|
|
throw new Error(`Required mailshot not found: ${mailshotPurpose}`);
|
|
}
|
|
const saved = await ensureMailshot(request, {
|
|
Purpose: purpose,
|
|
DataSource: effectiveDsName,
|
|
CC: '',
|
|
BCC: '',
|
|
Subject: 'Renewal for {{ account_name }}',
|
|
Message: '',
|
|
PDFAttachment: renewalsTemplate,
|
|
AttachmentNames: '[]',
|
|
PDFFilenameDerivedFrom: 'account_name',
|
|
RecipientEmailField: '',
|
|
ReplyTo: ''
|
|
});
|
|
mailshotId = String(saved.id || '');
|
|
createdMailshot = true;
|
|
}
|
|
expect(mailshotId).not.toBe('');
|
|
|
|
const dsListFinal = await apiList(request, 'feca_mailshots_data_sources_api');
|
|
expect(dsListFinal.ok).toBeTruthy();
|
|
const effectiveDsExists = (dsListFinal.items || []).some((row) => String(row.name || '') === effectiveDsName);
|
|
expect(effectiveDsExists).toBeTruthy();
|
|
|
|
const render = await apiPost(request, 'feca_mailshots_test_api', 'render_test', {
|
|
mailshot_id: mailshotId,
|
|
recipient_index: '0'
|
|
});
|
|
expect(render.ok).toBeTruthy();
|
|
expect(String(render?.rendered?.pdf_attachment || '')).toContain('Membership Renewal');
|
|
|
|
return {
|
|
mailshotId,
|
|
cleanup: async () => {
|
|
await cleanupByNames(request, {
|
|
dataSourceNames: [dsCreatedName],
|
|
mailshotPurposes: createdMailshot ? [purpose] : []
|
|
});
|
|
}
|
|
};
|
|
};
|
|
|
|
test('downloads merged PDF for renewal_accounts_with_contacts', async ({ page, request }) => {
|
|
const resolved = await resolveMailshot(request);
|
|
try {
|
|
await page.goto(`${adminPath('feca-mailshots-download-pdf')}&mailshot_id=${encodeURIComponent(resolved.mailshotId)}`);
|
|
await expect(page.getByRole('heading', { name: 'Download PDF' })).toBeVisible();
|
|
await page.locator('#dp_mailshot_id').selectOption(resolved.mailshotId);
|
|
|
|
await clickAndExpectDownload(page, 'Download Merged PDF', '_merged.pdf');
|
|
} finally {
|
|
try {
|
|
await resolved.cleanup();
|
|
} catch {
|
|
// best effort cleanup
|
|
}
|
|
}
|
|
});
|
|
|
|
test('downloads ZIP of PDFs for renewal_accounts_with_contacts', async ({ page, request }) => {
|
|
const resolved = await resolveMailshot(request);
|
|
try {
|
|
await page.goto(`${adminPath('feca-mailshots-download-pdf')}&mailshot_id=${encodeURIComponent(resolved.mailshotId)}`);
|
|
await expect(page.getByRole('heading', { name: 'Download PDF' })).toBeVisible();
|
|
await page.locator('#dp_mailshot_id').selectOption(resolved.mailshotId);
|
|
await clickAndExpectDownload(page, 'Download ZIP of PDFs', '_pdfs.zip');
|
|
} finally {
|
|
try {
|
|
await resolved.cleanup();
|
|
} catch {
|
|
// best effort cleanup
|
|
}
|
|
}
|
|
});
|
|
});
|