test(admin-web): Rich media E2E tests for broadcasts
- Create broadcasts with single/multiple media items - Upload media via blob storage - Validate media URLs - Reorder and remove media - User dashboard media display and lightbox - Video playback and media view tracking
This commit is contained in:
parent
3efdd97057
commit
8d7d8e4e18
231
dashboards/admin-web/e2e/rich-media.spec.ts
Normal file
231
dashboards/admin-web/e2e/rich-media.spec.ts
Normal file
@ -0,0 +1,231 @@
|
||||
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();
|
||||
await page.waitForURL('**/dashboard', { timeout: 10000 });
|
||||
}
|
||||
|
||||
test.describe('Rich Media Broadcasts', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await loginAsAdmin(page);
|
||||
await page.click('text=Broadcasts');
|
||||
});
|
||||
|
||||
test('creates broadcast with single image', async ({ page }) => {
|
||||
await page.click('text=Create broadcast');
|
||||
|
||||
// Fill basic info
|
||||
await page.getByLabel('Title').fill('Image Broadcast Test');
|
||||
await page.getByLabel('Body').fill('Check out this image!');
|
||||
|
||||
// Add image
|
||||
await page.click('text=Media');
|
||||
await page.getByLabel('Image URL').fill('https://example.com/image.jpg');
|
||||
|
||||
// Save
|
||||
await page.click('text=Save Draft');
|
||||
await expect(page.getByText('Broadcast saved')).toBeVisible();
|
||||
});
|
||||
|
||||
test('creates broadcast with multiple media items', async ({ page }) => {
|
||||
await page.click('text=Create broadcast');
|
||||
|
||||
await page.getByLabel('Title').fill('Gallery Broadcast');
|
||||
await page.getByLabel('Body').fill('Multiple images and video');
|
||||
|
||||
// Go to media tab
|
||||
await page.click('text=Media');
|
||||
|
||||
// Add first image
|
||||
await page.click('text=Add Media');
|
||||
await page.getByPlaceholder('Media URL').fill('https://example.com/photo1.jpg');
|
||||
await page.selectOption('select[name="mediaType"]', 'image');
|
||||
await page.click('text=Add');
|
||||
|
||||
// Add video
|
||||
await page.click('text=Add Media');
|
||||
await page.getByPlaceholder('Media URL').fill('https://example.com/video.mp4');
|
||||
await page.selectOption('select[name="mediaType"]', 'video');
|
||||
await page.getByPlaceholder('Thumbnail URL').fill('https://example.com/thumb.jpg');
|
||||
await page.fill('input[name="duration"]', '120');
|
||||
await page.click('text=Add');
|
||||
|
||||
// Verify media list
|
||||
await expect(page.getByText('photo1.jpg')).toBeVisible();
|
||||
await expect(page.getByText('video.mp4')).toBeVisible();
|
||||
|
||||
// Save
|
||||
await page.click('text=Save Draft');
|
||||
await expect(page.getByText('Broadcast saved')).toBeVisible();
|
||||
});
|
||||
|
||||
test('displays media gallery in broadcast preview', async ({ page }) => {
|
||||
// Create broadcast with media first
|
||||
await page.click('text=Create broadcast');
|
||||
await page.getByLabel('Title').fill('Preview Test');
|
||||
await page.click('text=Media');
|
||||
await page.getByLabel('Image URL').fill('https://example.com/preview.jpg');
|
||||
await page.click('text=Save Draft');
|
||||
|
||||
// Go back to list and open preview
|
||||
await page.click('text=Broadcasts');
|
||||
await page.locator('tr:has-text("Preview Test")').getByRole('button', { name: 'Preview' }).click();
|
||||
|
||||
// Verify media in preview modal
|
||||
await expect(page.locator('img[src*="preview.jpg"]')).toBeVisible();
|
||||
});
|
||||
|
||||
test('tracks media engagement in analytics', async ({ page }) => {
|
||||
// Find a sent broadcast with media
|
||||
await page.click('text=Broadcasts');
|
||||
const mediaRow = page.locator('tr:has-text("Gallery Broadcast")').first();
|
||||
|
||||
if (await mediaRow.isVisible().catch(() => false)) {
|
||||
await mediaRow.getByText('Analytics').click();
|
||||
|
||||
// Check media metrics
|
||||
await expect(page.getByText('Media Views')).toBeVisible();
|
||||
await expect(page.getByText('Media Completions')).toBeVisible();
|
||||
await expect(page.getByText('Media Clicks')).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('uploads media via blob storage', async ({ page }) => {
|
||||
await page.click('text=Create broadcast');
|
||||
await page.getByLabel('Title').fill('Upload Test');
|
||||
|
||||
// Go to media tab
|
||||
await page.click('text=Media');
|
||||
|
||||
// Upload file
|
||||
const fileInput = page.locator('input[type="file"]');
|
||||
await fileInput.setInputFiles({
|
||||
name: 'test-image.png',
|
||||
mimeType: 'image/png',
|
||||
buffer: Buffer.from('fake-image-data'),
|
||||
});
|
||||
|
||||
// Wait for upload
|
||||
await expect(page.getByText('Uploading...')).toBeVisible();
|
||||
await expect(page.getByText('Upload complete')).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// Verify uploaded media appears
|
||||
await expect(page.getByText('test-image.png')).toBeVisible();
|
||||
});
|
||||
|
||||
test('validates media URLs', async ({ page }) => {
|
||||
await page.click('text=Create broadcast');
|
||||
await page.getByLabel('Title').fill('Validation Test');
|
||||
|
||||
// Try invalid URL
|
||||
await page.click('text=Media');
|
||||
await page.getByLabel('Image URL').fill('not-a-valid-url');
|
||||
await page.click('text=Save Draft');
|
||||
|
||||
// Should show validation error
|
||||
await expect(page.getByText('Invalid URL')).toBeVisible();
|
||||
});
|
||||
|
||||
test('reorders media items', async ({ page }) => {
|
||||
await page.click('text=Create broadcast');
|
||||
await page.getByLabel('Title').fill('Reorder Test');
|
||||
|
||||
// Add multiple media
|
||||
await page.click('text=Media');
|
||||
await page.click('text=Add Media');
|
||||
await page.getByPlaceholder('Media URL').fill('https://example.com/first.jpg');
|
||||
await page.click('text=Add');
|
||||
|
||||
await page.click('text=Add Media');
|
||||
await page.getByPlaceholder('Media URL').fill('https://example.com/second.jpg');
|
||||
await page.click('text=Add');
|
||||
|
||||
// Reorder (move second to first)
|
||||
const secondItem = page.locator('[data-testid="media-item"]').nth(1);
|
||||
await secondItem.getByRole('button', { name: 'Move up' }).click();
|
||||
|
||||
// Verify order changed
|
||||
const items = page.locator('[data-testid="media-item"]');
|
||||
await expect(items.first()).toContainText('second.jpg');
|
||||
});
|
||||
|
||||
test('removes media from broadcast', async ({ page }) => {
|
||||
await page.click('text=Create broadcast');
|
||||
await page.getByLabel('Title').fill('Remove Test');
|
||||
|
||||
// Add then remove media
|
||||
await page.click('text=Media');
|
||||
await page.getByLabel('Image URL').fill('https://example.com/temp.jpg');
|
||||
|
||||
// Remove button should appear
|
||||
await page.getByRole('button', { name: 'Remove media' }).click();
|
||||
|
||||
// Verify removed
|
||||
await expect(page.getByLabel('Image URL')).toHaveValue('');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('User Dashboard Rich Media', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// Login as regular user
|
||||
await page.goto('/login');
|
||||
await page.getByLabel('Email').fill('user@example.com');
|
||||
await page.getByLabel('Password').fill('User123!');
|
||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
||||
await page.waitForURL('**/portal', { timeout: 10000 });
|
||||
});
|
||||
|
||||
test('displays media in broadcast banner', async ({ page }) => {
|
||||
// Wait for banner with media to appear
|
||||
const banner = page.locator('[data-testid="broadcast-banner"]').first();
|
||||
await expect(banner).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// Check for media thumbnail
|
||||
const mediaThumb = banner.locator('img');
|
||||
if (await mediaThumb.isVisible().catch(() => false)) {
|
||||
await expect(mediaThumb).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('opens media lightbox on click', async ({ page }) => {
|
||||
const banner = page.locator('[data-testid="broadcast-banner"]').first();
|
||||
await expect(banner).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// Click on media
|
||||
await banner.locator('img').click();
|
||||
|
||||
// Lightbox should open
|
||||
await expect(page.locator('[data-testid="media-lightbox"]')).toBeVisible();
|
||||
});
|
||||
|
||||
test('tracks media view in user dashboard', async ({ page }) => {
|
||||
// Open broadcast with media
|
||||
const banner = page.locator('[data-testid="broadcast-banner"]').first();
|
||||
await expect(banner).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// Click to view media
|
||||
await banner.locator('img').click();
|
||||
|
||||
// Analytics event should fire
|
||||
await expect(page.getByText('Media viewed')).toBeVisible();
|
||||
});
|
||||
|
||||
test('plays video in modal', async ({ page }) => {
|
||||
const banner = page.locator('[data-testid="broadcast-banner"]').first();
|
||||
await expect(banner).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// Check if banner has video
|
||||
const video = banner.locator('video');
|
||||
if (await video.isVisible().catch(() => false)) {
|
||||
// Click play
|
||||
await video.click();
|
||||
await expect(video).toHaveAttribute('autoplay');
|
||||
}
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user