import { test, expect } from '@playwright/test'; const ADMIN_EMAIL = 'admin@example.com'; const ADMIN_PASSWORD = 'Admin123!'; async function loginAsAdmin(page: any) { await page.goto('/login'); await page.getByLabel('Email').fill(ADMIN_EMAIL); await page.getByLabel('Password').fill(ADMIN_PASSWORD); await page.getByRole('button', { name: 'Sign In' }).click(); // Wait for redirect to dashboard await page.waitForURL('**/dashboard', { timeout: 10000 }); } test.describe('Broadcasts Admin', () => { test.beforeEach(async ({ page }) => { await loginAsAdmin(page); }); test('navigates to broadcasts page', async ({ page }) => { await page.click('text=Broadcasts'); await expect(page.getByText('Broadcasts')).toBeVisible(); await expect(page.getByText('Create broadcast')).toBeVisible(); }); test('shows broadcast list with filters', async ({ page }) => { await page.click('text=Broadcasts'); // Check filter dropdowns exist await expect(page.getByLabel('Status')).toBeVisible(); await expect(page.getByLabel('Channel')).toBeVisible(); // Check table headers await expect(page.getByText('Title')).toBeVisible(); await expect(page.getByText('Status')).toBeVisible(); await expect(page.getByText('Channel')).toBeVisible(); await expect(page.getByText('Metrics')).toBeVisible(); }); test('creates new broadcast draft', async ({ page }) => { await page.click('text=Broadcasts'); await page.click('text=Create broadcast'); // Should navigate to create page await expect(page).toHaveURL(/.*broadcasts\/new/); // Fill basic info await page.getByLabel('Title').fill('Test Broadcast'); await page.getByLabel('Body').fill('This is a test broadcast message'); // Select channel await page.getByLabel('Channel').selectOption('push'); await page.getByLabel('Priority').selectOption('normal'); await page.getByLabel('Style').selectOption('banner'); // Save as draft await page.click('text=Save Draft'); // Should show success and redirect await expect(page.getByText('Broadcast saved')).toBeVisible({ timeout: 5000 }); }); test('creates broadcast with targeting', async ({ page }) => { await page.click('text=Broadcasts'); await page.click('text=Create broadcast'); // Basic info await page.getByLabel('Title').fill('Targeted Broadcast'); await page.getByLabel('Body').fill('For pro users only'); // Go to targeting tab await page.click('text=Targeting'); // Select platforms await page.getByLabel('iOS').check(); await page.getByLabel('Android').check(); // Select user segments await page.getByLabel('User Segments').selectOption(['pro']); // Set percentage rollout await page.getByLabel('Percentage Rollout').fill('50'); // Go to schedule tab await page.click('text=Schedule'); await page.getByLabel('Send immediately').check(); // Send await page.click('text=Send Broadcast'); // Confirm dialog await page.click('text=Confirm'); await expect(page.getByText('Broadcast sent')).toBeVisible({ timeout: 5000 }); }); test('clones existing broadcast', async ({ page }) => { await page.click('text=Broadcasts'); // Find first broadcast row and click clone const firstRow = page.locator('table tbody tr').first(); await firstRow.getByRole('button', { name: 'Clone' }).click(); // Should be on new broadcast page with pre-filled data await expect(page).toHaveURL(/.*broadcasts\/new/); await expect(page.getByLabel('Title')).not.toHaveValue(''); }); test('pauses and resumes broadcast', async ({ page }) => { await page.click('text=Broadcasts'); // Find a sending broadcast const sendingRow = page.locator('tr:has-text("Sending")').first(); if (await sendingRow.isVisible().catch(() => false)) { await sendingRow.getByRole('button', { name: 'Pause' }).click(); await expect(page.getByText('Broadcast paused')).toBeVisible(); // Resume await sendingRow.getByRole('button', { name: 'Resume' }).click(); await expect(page.getByText('Broadcast resumed')).toBeVisible(); } }); test('views broadcast metrics', async ({ page }) => { await page.click('text=Broadcasts'); // Click on first broadcast title await page.locator('table tbody tr td:first-child a').first().click(); // Should show detail page await expect(page.getByText('Metrics')).toBeVisible(); await expect(page.getByText('Targeted')).toBeVisible(); await expect(page.getByText('Sent')).toBeVisible(); await expect(page.getByText('Delivered')).toBeVisible(); await expect(page.getByText('Opened')).toBeVisible(); await expect(page.getByText('Clicked')).toBeVisible(); }); test('deletes broadcast', async ({ page }) => { await page.click('text=Broadcasts'); // Find a draft broadcast to delete const draftRow = page.locator('tr:has-text("Draft")').first(); if (await draftRow.isVisible().catch(() => false)) { await draftRow.getByRole('button', { name: 'Delete' }).click(); // Confirm delete await page.click('text=Confirm Delete'); await expect(page.getByText('Broadcast deleted')).toBeVisible(); } }); }); test.describe('Surveys Admin', () => { test.beforeEach(async ({ page }) => { await loginAsAdmin(page); }); test('navigates to surveys page', async ({ page }) => { await page.click('text=Surveys'); await expect(page.getByText('Surveys')).toBeVisible(); await expect(page.getByText('Create survey')).toBeVisible(); }); test('shows survey list', async ({ page }) => { await page.click('text=Surveys'); // Check table headers await expect(page.getByText('Title')).toBeVisible(); await expect(page.getByText('Status')).toBeVisible(); await expect(page.getByText('Responses')).toBeVisible(); await expect(page.getByText('Completion Rate')).toBeVisible(); }); test('creates new survey with NPS question', async ({ page }) => { await page.click('text=Surveys'); await page.click('text=Create survey'); // Should navigate to builder page await expect(page).toHaveURL(/.*surveys\/new/); // Fill basic info await page.getByLabel('Survey Title').fill('NPS Survey Test'); await page.getByLabel('Description').fill('How likely are you to recommend us?'); // Add NPS question await page.click('text=Add Question'); await page.selectOption('select[name="questionType"]', 'nps'); await page.getByLabel('Question Text').fill('How likely are you to recommend us to a friend?'); await page.click('text=Add'); // Add multiple choice question await page.click('text=Add Question'); await page.selectOption('select[name="questionType"]', 'single_choice'); await page.getByLabel('Question Text').fill('What is your primary use case?'); // Add options await page.click('text=Add Option'); await page.getByPlaceholder('Option text').fill('Voice dictation'); await page.click('text=Add Option'); await page.getByPlaceholder('Option text').nth(1).fill('Keyboard'); await page.click('text=Add'); // Save survey await page.click('text=Save Survey'); await expect(page.getByText('Survey saved')).toBeVisible({ timeout: 5000 }); }); test('creates survey with conditional logic', async ({ page }) => { await page.click('text=Surveys'); await page.click('text=Create survey'); // Basic info await page.getByLabel('Survey Title').fill('Conditional Survey'); // Add first question (NPS) await page.click('text=Add Question'); await page.selectOption('select[name="questionType"]', 'nps'); await page.getByLabel('Question Text').fill('Rate your experience'); await page.click('text=Add'); // Add conditional follow-up question await page.click('text=Add Question'); await page.selectOption('select[name="questionType"]', 'text_long'); await page.getByLabel('Question Text').fill('What can we improve?'); // Set conditional logic await page.click('text=Conditional Logic'); await page.selectOption('select[name="conditionQuestion"]', 'q1'); await page.selectOption('select[name="conditionOperator"]', 'not_equals'); await page.fill('input[name="conditionValue"]', '9,10'); await page.click('text=Add'); // Save await page.click('text=Save Survey'); await expect(page.getByText('Survey saved')).toBeVisible(); }); test('activates and pauses survey', async ({ page }) => { await page.click('text=Surveys'); // Find a draft survey const draftRow = page.locator('tr:has-text("Draft")').first(); if (await draftRow.isVisible().catch(() => false)) { // Click activate await draftRow.getByRole('button', { name: 'Activate' }).click(); await expect(page.getByText('Survey activated')).toBeVisible(); // Find the now-active survey and pause it const activeRow = page.locator('tr:has-text("Active")').first(); await activeRow.getByRole('button', { name: 'Pause' }).click(); await expect(page.getByText('Survey paused')).toBeVisible(); } }); test('views survey metrics', async ({ page }) => { await page.click('text=Surveys'); // Click on first survey await page.locator('table tbody tr td:first-child a').first().click(); // Should show detail page with tabs await expect(page.getByText('Overview')).toBeVisible(); await expect(page.getByText('Questions')).toBeVisible(); await expect(page.getByText('Responses')).toBeVisible(); await expect(page.getByText('Analytics')).toBeVisible(); // Click Analytics tab await page.click('text=Analytics'); await expect(page.getByText('Completion Rate')).toBeVisible(); await expect(page.getByText('Average Time')).toBeVisible(); }); test('exports survey responses', async ({ page }) => { await page.click('text=Surveys'); // Click on first survey await page.locator('table tbody tr td:first-child a').first().click(); // Go to Responses tab await page.click('text=Responses'); // Click export await page.click('text=Export'); // Wait for download or success message await expect(page.getByText('Export started')).toBeVisible(); }); test('sets survey incentive', async ({ page }) => { await page.click('text=Surveys'); await page.click('text=Create survey'); // Basic info await page.getByLabel('Survey Title').fill('Incentivized Survey'); // Go to Settings tab await page.click('text=Settings'); // Enable incentive await page.getByLabel('Enable Incentive').check(); await page.selectOption('select[name="incentiveType"]', 'pro_days'); await page.getByLabel('Incentive Amount').fill('7'); // Add question await page.click('text=Questions'); await page.click('text=Add Question'); await page.selectOption('select[name="questionType"]', 'nps'); await page.getByLabel('Question Text').fill('How likely are you to recommend us?'); await page.click('text=Add'); // Save await page.click('text=Save Survey'); await expect(page.getByText('Survey saved')).toBeVisible(); }); test('configures survey targeting', async ({ page }) => { await page.click('text=Surveys'); await page.click('text=Create survey'); // Basic info await page.getByLabel('Survey Title').fill('Targeted Survey'); // Go to Targeting tab await page.click('text=Targeting'); // Select platforms await page.getByLabel('iOS').check(); await page.getByLabel('Android').check(); // Select user segments await page.getByLabel('Active Users').check(); await page.getByLabel('Pro Users').check(); // Set rollout await page.getByLabel('Percentage Rollout').fill('25'); // Add question await page.click('text=Questions'); await page.click('text=Add Question'); await page.selectOption('select[name="questionType"]', 'rating'); await page.getByLabel('Question Text').fill('Rate the app'); await page.click('text=Add'); // Save await page.click('text=Save Survey'); await expect(page.getByText('Survey saved')).toBeVisible(); }); }); test.describe('Broadcast & Survey Integration', () => { test.beforeEach(async ({ page }) => { await loginAsAdmin(page); }); test('sidebar navigation shows both sections', async ({ page }) => { await expect(page.getByText('Broadcasts')).toBeVisible(); await expect(page.getByText('Surveys')).toBeVisible(); }); test('can navigate between broadcasts and surveys', async ({ page }) => { // Go to broadcasts await page.click('text=Broadcasts'); await expect(page.getByText('Create broadcast')).toBeVisible(); // Go to surveys await page.click('text=Surveys'); await expect(page.getByText('Create survey')).toBeVisible(); // Back to broadcasts await page.click('text=Broadcasts'); await expect(page.getByText('Create broadcast')).toBeVisible(); }); });