import { test, expect } from '@playwright/test';
import { adminPath, ensureDataSource, ensureMailshot, cleanupByNames } from './helpers.mjs';
test.describe('new selected-rows and all-recipients features', () => {
test('mailshot test: all recipients uses count-based confirm text', async ({ page, request }) => {
const uniq = `${Date.now()}_${Math.floor(Math.random() * 100000)}`;
const dsName = `e2e_newfeat_ds_${uniq}`;
const purpose = `e2e_newfeat_ms_${uniq}`;
try {
await ensureDataSource(request, dsName, 'contacts');
const saved = await ensureMailshot(request, {
Purpose: purpose,
DataSource: dsName,
CC: '',
BCC: '',
Subject: 'Subj {{ contacts_id }}',
Message: '
Hi {{ contacts_id }}
',
PDFAttachment: 'PDF
',
AttachmentNames: '[]',
PDFFilenameDerivedFrom: '',
RecipientEmailField: 'contacts.contact_email_1',
ReplyTo: ''
});
await page.goto(`${adminPath('feca-mailshots-test')}&mailshot_id=${encodeURIComponent(String(saved.id || ''))}`);
await expect(page.getByRole('heading', { name: 'Mailshot Test' })).toBeVisible();
await expect(page.locator('#mst_recipient_index')).toBeVisible();
await page.locator('#mst_recipient_index').selectOption('-1');
const recipientCount = await page.locator('#mst_recipient_index').evaluate((el) => {
const raw = el.getAttribute('data-recipient-count') || '0';
const n = Number.parseInt(raw, 10);
return Number.isFinite(n) && n >= 0 ? n : 0;
});
let dialogText = '';
page.once('dialog', async (dialog) => {
dialogText = dialog.message();
await dialog.dismiss();
});
await page.getByRole('button', { name: 'Send Test Email' }).click();
await expect.poll(() => dialogText).toContain(`Send ${recipientCount} emails to the entered address?`);
} finally {
try {
await cleanupByNames(request, { dataSourceNames: [dsName], mailshotPurposes: [purpose] });
} catch {
// best effort
}
}
});
test('review recipients: row selection persists in session and selected count updates', async ({ page, request }) => {
const uniq = `${Date.now()}_${Math.floor(Math.random() * 100000)}`;
const dsName = `e2e_rrsel_ds_${uniq}`;
try {
await ensureDataSource(request, dsName, 'contacts');
await page.goto(`${adminPath('feca-mailshots-review-recipients')}&data_source=${encodeURIComponent(dsName)}`);
await expect(page.getByRole('heading', { name: 'Review Recipients' })).toBeVisible();
const firstRowCheckbox = page.locator('#rr_body input.rr-row-select').first();
await expect(firstRowCheckbox).toBeVisible({ timeout: 20000 });
await firstRowCheckbox.check();
await expect(page.locator('#rr_status')).toContainText('Selected: 1');
await page.goto(adminPath('feca-mailshots-mailshots'));
await expect(page.locator('h1', { hasText: 'Mailshots' })).toBeVisible();
await page.goto(`${adminPath('feca-mailshots-review-recipients')}&data_source=${encodeURIComponent(dsName)}`);
await expect(page.locator('#rr_body input.rr-row-select').first()).toBeChecked({ timeout: 20000 });
await expect(page.locator('#rr_status')).toContainText('Selected: 1');
} finally {
try {
await cleanupByNames(request, { dataSourceNames: [dsName], mailshotPurposes: [] });
} catch {
// best effort
}
}
});
test('run mailshot: selected-rows action shows guard and count-based confirm', async ({ page, request }) => {
const uniq = `${Date.now()}_${Math.floor(Math.random() * 100000)}`;
const dsName = `e2e_runsel_ds_${uniq}`;
const purpose = `e2e_runsel_ms_${uniq}`;
try {
await ensureDataSource(request, dsName, 'contacts');
const saved = await ensureMailshot(request, {
Purpose: purpose,
DataSource: dsName,
CC: '',
BCC: '',
Subject: 'Subj {{ contacts_id }}',
Message: 'Hi {{ contacts_id }}
',
PDFAttachment: 'PDF
',
AttachmentNames: '[]',
PDFFilenameDerivedFrom: '',
RecipientEmailField: 'contacts.contact_email_1',
ReplyTo: ''
});
await page.goto(`${adminPath('feca-mailshots-run')}&mailshot_id=${encodeURIComponent(String(saved.id || ''))}`);
await expect(page.getByRole('heading', { name: 'Run Mailshot' })).toBeVisible();
await expect(page.locator('#run-mailshot-selected-btn')).toBeVisible();
await expect(page.locator('#feca-run-actions-form a', { hasText: 'Review Recipients' })).toBeVisible();
let guardDialog = '';
page.once('dialog', async (dialog) => {
guardDialog = dialog.message();
await dialog.accept();
});
await page.locator('#run-mailshot-selected-btn').click();
await expect.poll(() => guardDialog).toContain('No selected rows found');
await page.evaluate((sourceName) => {
const key = `fecaReviewRecipientsSelection::${sourceName}`;
sessionStorage.setItem(key, JSON.stringify({ 'row_index:0': true, 'row_index:1': true }));
}, dsName);
let confirmDialog = '';
page.once('dialog', async (dialog) => {
confirmDialog = dialog.message();
await dialog.dismiss();
});
await page.locator('#run-mailshot-selected-btn').click();
await expect.poll(() => confirmDialog).toContain('Run Mailshot to 2 selected rows?');
} finally {
try {
await cleanupByNames(request, { dataSourceNames: [dsName], mailshotPurposes: [purpose] });
} catch {
// best effort
}
}
});
});