Fix: Display correct SmoothSchedule logo in email preview

Replaced the blank base64 encoded logo with the actual SmoothSchedule logo in the email rendering pipeline.

A Playwright E2E test was run to verify that the logo is correctly displayed in the email preview modal, ensuring it loads with natural dimensions and is visible.
This commit is contained in:
poduck
2025-12-14 19:10:56 -05:00
parent fbefccf436
commit 89fa8f81af
80 changed files with 7398 additions and 7908 deletions

View File

@@ -0,0 +1,123 @@
import { test, expect } from '@playwright/test';
test.describe('Email Preview Logo', () => {
test('should display SmoothSchedule logo in email preview', async ({ page }) => {
// Increase timeout for this test
test.setTimeout(90000);
// Go directly to the business subdomain login
await page.goto('http://pixel8ed.lvh.me:5173/login');
await page.waitForLoadState('networkidle');
// Login using input types
const emailInput = page.locator('input[type="email"]');
const passwordInput = page.locator('input[type="password"]');
await expect(emailInput).toBeVisible({ timeout: 10000 });
await emailInput.fill('timm50@hotmail.com');
await passwordInput.fill('starry12');
// Click sign in button
await page.getByRole('button', { name: /sign in/i }).click();
// Wait for navigation after login
await page.waitForURL(/pixel8ed\.lvh\.me:5173/, { timeout: 15000 });
await page.waitForLoadState('networkidle');
await page.waitForTimeout(2000);
// Navigate to email templates
await page.goto('http://pixel8ed.lvh.me:5173/dashboard/settings/email-templates');
await page.waitForLoadState('networkidle');
await page.waitForTimeout(2000);
// Click the first template's expand button
const templateCards = page.locator('.space-y-4 > div');
const firstCard = templateCards.first();
const cardButtons = firstCard.locator('button');
const buttonCount = await cardButtons.count();
console.log(`Found ${buttonCount} buttons in first card`);
if (buttonCount > 0) {
await cardButtons.last().click();
await page.waitForTimeout(1000);
}
// Click the Preview button
const previewButton = page.getByRole('button', { name: /preview/i });
await expect(previewButton).toBeVisible({ timeout: 5000 });
await previewButton.click();
// Wait for modal to appear
await page.waitForTimeout(2000);
// Find the iframe using frameLocator
const iframeLocator = page.locator('iframe[title="Email Preview"]');
await expect(iframeLocator).toBeVisible({ timeout: 5000 });
// Wait for iframe content to load
await page.waitForTimeout(1500);
// Use frameLocator to access iframe content
const frame = page.frameLocator('iframe[title="Email Preview"]');
// Look for the branding section with the logo
const brandingImg = frame.locator('img[alt="SmoothSchedule"]');
// Scroll the iframe element itself to see the footer
await brandingImg.scrollIntoViewIfNeeded();
await page.waitForTimeout(500);
// Check if image exists
const imgCount = await brandingImg.count();
console.log(`Found ${imgCount} SmoothSchedule logo image(s)`);
if (imgCount > 0) {
// Check if the image has a valid src (data URL)
const imgSrc = await brandingImg.first().getAttribute('src');
console.log(`Image src starts with: ${imgSrc?.substring(0, 50)}`);
// Verify it's a data URL
expect(imgSrc).toContain('data:image/png;base64');
// Check all image attributes
const width = await brandingImg.first().getAttribute('width');
const height = await brandingImg.first().getAttribute('height');
const style = await brandingImg.first().getAttribute('style');
console.log(`Image attributes - width: ${width}, height: ${height}, style: ${style}`);
// Check if image has natural dimensions (meaning it loaded)
const naturalWidth = await brandingImg.first().evaluate((img: HTMLImageElement) => img.naturalWidth);
const naturalHeight = await brandingImg.first().evaluate((img: HTMLImageElement) => img.naturalHeight);
console.log(`Image natural dimensions: ${naturalWidth}x${naturalHeight}`);
// Check computed/displayed dimensions
const boundingBox = await brandingImg.first().boundingBox();
console.log(`Image bounding box: ${JSON.stringify(boundingBox)}`);
// Check if parent element is visible
const parentHtml = await brandingImg.first().evaluate((img) => img.parentElement?.outerHTML);
console.log(`Parent element: ${parentHtml?.substring(0, 300)}`);
expect(naturalWidth).toBeGreaterThan(0);
expect(naturalHeight).toBeGreaterThan(0);
// Check if image is actually visible (has non-zero display dimensions)
if (boundingBox) {
console.log(`Image displayed at ${boundingBox.width}x${boundingBox.height} pixels`);
expect(boundingBox.width).toBeGreaterThan(0);
expect(boundingBox.height).toBeGreaterThan(0);
}
// Take screenshot focused on the branding area
await page.screenshot({ path: 'test-results/email-preview-footer.png', fullPage: true });
console.log('SUCCESS: Logo image loaded correctly');
} else {
// Debug: get the HTML
const html = await frame.locator('body').innerHTML();
console.log('Iframe body HTML:', html);
throw new Error('SmoothSchedule logo image not found in iframe');
}
});
});

View File

@@ -0,0 +1,94 @@
import { test, expect } from '@playwright/test';
test.describe('Email Template Editor', () => {
test.beforeEach(async ({ page }) => {
// Login with real credentials on the pixel8ed subdomain
await page.goto('http://pixel8ed.lvh.me:5173/login');
// Wait for the login form
await expect(page.locator('input[type="email"]')).toBeVisible({ timeout: 10000 });
// Fill in the login form
await page.fill('input[type="email"]', 'timm50@hotmail.com');
await page.fill('input[type="password"]', 'starry12');
// Click sign in button
await page.click('button[type="submit"]');
// Wait for login to complete and redirect to dashboard
await page.waitForURL('**/dashboard**', { timeout: 20000 });
});
test('should check site builder works correctly', async ({ page }) => {
// Navigate directly to site builder
await page.goto('http://pixel8ed.lvh.me:5173/dashboard/site-editor', { waitUntil: 'networkidle' });
await page.waitForTimeout(3000);
// Take screenshot
await page.screenshot({ path: 'test-results/site-builder-state.png', fullPage: true });
// Check iframe content for multiple component types
const iframe = page.frameLocator('iframe').first();
try {
const iframeContent = await iframe.locator('body').textContent({ timeout: 3000 });
console.log('Site builder iframe content (first 500 chars):', iframeContent?.substring(0, 500));
// Site builder should have diverse content
expect(iframeContent?.length).toBeGreaterThan(100);
} catch (e) {
console.log('No iframe content found');
}
});
test('should check email template editor with actual API data', async ({ page }) => {
// Navigate directly to the dedicated email template editor page
await page.goto('http://pixel8ed.lvh.me:5173/dashboard/email-template-editor/welcome', { waitUntil: 'networkidle' });
// Wait for editor to load - need to wait for Puck to render
await expect(page.getByText(/Email Subject/i)).toBeVisible({ timeout: 10000 });
// Wait for Puck editor to appear (Components heading)
await expect(page.getByRole('heading', { name: 'Components' })).toBeVisible({ timeout: 15000 });
await page.waitForTimeout(3000);
// Take screenshot
await page.screenshot({ path: 'test-results/email-editor-api-data.png', fullPage: true });
// Count component types shown
const emailHeaderCount = await page.locator('text="Email Header"').count();
const emailHeadingCount = await page.locator('text="Email Heading"').count();
const emailTextCount = await page.locator('text="Email Text"').count();
const emailButtonCount = await page.locator('text="Email Button"').count();
const emailSpacerCount = await page.locator('text="Email Spacer"').count();
const emailFooterCount = await page.locator('text="Email Footer"').count();
console.log('Component type counts in editor:');
console.log(' Email Header:', emailHeaderCount);
console.log(' Email Heading:', emailHeadingCount);
console.log(' Email Text:', emailTextCount);
console.log(' Email Button:', emailButtonCount);
console.log(' Email Spacer:', emailSpacerCount);
console.log(' Email Footer:', emailFooterCount);
// Check iframe content for diverse component rendering
const iframe = page.frameLocator('iframe').first();
try {
const iframeContent = await iframe.locator('body').textContent({ timeout: 3000 });
console.log('Iframe content (first 800 chars):', iframeContent?.substring(0, 800));
// Content should show diverse email template components
expect(iframeContent?.length).toBeGreaterThan(100);
} catch (e) {
console.log('No iframe content found');
}
// With correct config, we should see multiple different component types
// If the bug is fixed, no single component type should dominate
const maxCount = Math.max(emailHeaderCount, emailHeadingCount, emailTextCount,
emailButtonCount, emailSpacerCount, emailFooterCount);
console.log('Max single component type count:', maxCount);
// A working editor should have reasonable distribution (max ~4-5 per type)
expect(maxCount).toBeLessThanOrEqual(5);
});
});

View File

@@ -0,0 +1,29 @@
import { test, expect } from '@playwright/test';
test('Site builder renders different components', async ({ page }) => {
// Login
await page.goto('http://pixel8ed.lvh.me:5173/login');
await page.getByPlaceholder(/username/i).fill('pixel8ed');
await page.getByPlaceholder(/password/i).fill('starry12');
await page.getByRole('button', { name: /sign in/i }).click();
// Navigate to site builder
await page.waitForTimeout(2000);
await page.goto('http://pixel8ed.lvh.me:5173/dashboard/site-editor');
await page.waitForTimeout(5000);
// Take screenshot
await page.screenshot({ path: 'test-results/site-builder-state.png', fullPage: true });
// Check for component variety in the iframe
const iframe = page.frameLocator('iframe');
const iframeContent = await iframe.locator('body').textContent().catch(() => '');
console.log('=== SITE BUILDER TEST ===');
console.log('Iframe content (first 500 chars):', iframeContent?.substring(0, 500));
// Check the Outline section for component names
const outlineSection = page.locator('h2:has-text("Outline")').locator('..').locator('..');
const outlineText = await outlineSection.textContent().catch(() => 'Not found');
console.log('Outline section:', outlineText?.substring(0, 500));
});