import { test, expect } from '@playwright/test'; test.describe('Nur Falah — Human-like UAT Journey', () => { test.setTimeout(120000); // 2 minutes for full journey test('Complete user journey: Prayer → Quran → Tasbih → Names', async ({ page }) => { // --- ARRIVE --- await page.goto('/'); await page.waitForSelector('.brand-name:has-text("Nur")'); await page.waitForTimeout(1000); // Human pause to orient // Verify brand await expect(page.locator('.brand-name')).toHaveText('Nur'); await expect(page.locator('.brand-accent')).toHaveText('Falah'); console.log('✅ Landed on Nur Falah home'); // --- PRAYER TIMES TAB --- await page.hover('nav .tab:has-text("Prayer")'); await page.waitForTimeout(300); await page.click('nav .tab:has-text("Prayer")'); await page.waitForTimeout(800); // Wait for API await expect(page.locator('.card h2')).toHaveText('🕌 Prayer Times'); await page.waitForSelector('.prayer-row', { timeout: 15000 }); const prayerRows = page.locator('.prayer-row'); await expect(prayerRows).toHaveCount(6); console.log('✅ Prayer times loaded (6 prayers)'); // Scroll through prayer times for (let i = 0; i < 3; i++) { await page.hover(`.prayer-row:nth-child(${i + 1})`); await page.waitForTimeout(400); } // Change calculation method await page.hover('.method-select select'); await page.waitForTimeout(200); await page.selectOption('.method-select select', '4'); // Umm al-Qura await page.waitForTimeout(1000); // Wait for refetch console.log('✅ Changed calculation method to Umm al-Qura'); // Enable notifications const notifyToggle = page.locator('.toggle-label input'); if (await notifyToggle.isEnabled()) { await notifyToggle.check(); await page.waitForTimeout(500); console.log('✅ Enabled prayer notifications'); } // --- QIBLA TAB --- await page.hover('nav .tab:has-text("Qibla")'); await page.waitForTimeout(300); await page.click('nav .tab:has-text("Qibla")'); await page.waitForTimeout(1500); // Compass init await expect(page.locator('.card h2')).toHaveText('🧭 Qibla Finder'); await page.waitForSelector('.compass', { timeout: 15000 }); // Watch compass needle await page.hover('.compass'); await page.waitForTimeout(2000); console.log('✅ Qibla compass displayed'); // --- QURAN TAB --- await page.hover('nav .tab:has-text("Quran")'); await page.waitForTimeout(300); await page.click('nav .tab:has-text("Quran")'); await page.waitForTimeout(2000); // Surah list load await expect(page.locator('.card h2')).toHaveText('📖 Holy Quran'); await page.waitForSelector('.surah-btn', { timeout: 15000 }); const surahCount = await page.locator('.surah-btn').count(); expect(surahCount).toBe(114); console.log(`✅ Surah list loaded (${surahCount} surahs)`); // Scroll through first 5 surahs for (let i = 0; i < 5; i++) { await page.hover(`.surah-btn:nth-child(${i + 1})`); await page.waitForTimeout(300); } // Open Al-Fatiha await page.click('.surah-btn:first-child'); await page.waitForTimeout(1500); await expect(page.locator('.back-btn')).toHaveText('← Surahs'); await expect(page.locator('.surah-title-block h3')).toHaveText('Al-Faatiha'); console.log('✅ Opened Al-Fatiha (Surah 1)'); // Toggle Arabic/English await page.hover('.view-toggles label:has-text("Arabic")'); await page.waitForTimeout(200); await page.uncheck('.view-toggles input[type="checkbox"]:nth-child(1)'); // Uncheck Arabic await page.waitForTimeout(300); await page.check('.view-toggles input[type="checkbox"]:nth-child(1)'); // Re-check Arabic await page.waitForTimeout(300); console.log('✅ Toggled Arabic/English view'); // Play first ayah audio await page.waitForSelector('.audio-btn', { timeout: 10000 }).catch(() => {}); const audioBtn = page.locator('.audio-btn').first(); if (await audioBtn.isVisible()) { await audioBtn.hover(); await page.waitForTimeout(300); await audioBtn.click(); await page.waitForTimeout(3000); console.log('✅ Played ayah audio'); } else { console.log('⚠️ Audio button not visible, skipping'); } // Go back to surah list await page.click('.back-btn'); await page.waitForTimeout(800); // --- HIJRI TAB --- await page.hover('nav .tab:has-text("Hijri")'); await page.waitForTimeout(300); await page.click('nav .tab:has-text("Hijri")'); await page.waitForTimeout(1000); await expect(page.locator('.card h2')).toHaveText('📅 Hijri Calendar'); await page.waitForSelector('.hijri-day', { timeout: 10000 }); const hijriDay = await page.locator('.hijri-day').textContent(); console.log(`✅ Hijri date: ${hijriDay} ${await page.locator('.hijri-month').textContent()} ${await page.locator('.hijri-year').textContent()}`); // Scroll through info rows for (let i = 0; i < 4; i++) { await page.hover(`.info-row:nth-child(${i + 1})`); await page.waitForTimeout(300); } // --- TASBIH TAB --- await page.hover('nav .tab:has-text("Tasbih")'); await page.waitForTimeout(300); await page.click('nav .tab:has-text("Tasbih")'); await page.waitForTimeout(500); await expect(page.locator('.card h2')).toHaveText('📿 Tasbih Counter'); // Count 33 (one full cycle) for (let i = 0; i < 5; i++) { await page.click('.counter-ring'); await page.waitForTimeout(150); } await expect(page.locator('.counter-ring text').first()).toHaveText('5'); console.log('✅ Tasbih counter incremented'); // Change target to 99 await page.selectOption('#bead-select', '99'); await page.waitForTimeout(300); console.log('✅ Changed target to 99'); // Reset await page.click('button.secondary:has-text("Reset")'); await expect(page.locator('.counter-ring text').first()).toHaveText('0'); console.log('✅ Reset counter'); // --- 99 NAMES TAB --- await page.hover('nav .tab:has-text("99 Names")'); await page.waitForTimeout(300); await page.click('nav .tab:has-text("99 Names")'); await page.waitForTimeout(1000); await expect(page.locator('.card h2')).toHaveText('💚 99 Names of Allah'); await page.waitForSelector('.name-card', { timeout: 10000 }); const nameCount = await page.locator('.name-card').count(); expect(nameCount).toBe(99); console.log(`✅ 99 Names loaded (${nameCount} names)`); // Scroll through first 10 for (let i = 0; i < 10; i++) { await page.hover(`.name-card:nth-child(${i + 1})`); await page.waitForTimeout(200); } // Expand first name await page.click('.name-card:first-child'); await page.waitForTimeout(500); await expect(page.locator('.name-card.expanded .name-meaning')).toHaveText('The Most Merciful'); console.log('✅ Expanded first name (Ar-Rahman)'); // Search await page.fill('.search-input', 'Rahman'); await page.waitForTimeout(500); const filtered = await page.locator('.name-card').evaluateAll(cards => cards.filter(c => c.offsetParent !== null).length ); expect(filtered).toBeGreaterThanOrEqual(1); console.log(`✅ Search "Rahman" returned ${filtered} results`); // Clear search await page.fill('.search-input', ''); await page.waitForTimeout(300); await expect(page.locator('.name-card')).toHaveCount(99); // --- PWA VERIFICATION --- await page.goto('/'); await page.waitForSelector('.brand-name:has-text("Nur")'); const manifest = page.locator('link[rel="manifest"]').first(); await expect(manifest).toHaveAttribute('href', '/manifest.webmanifest'); const themeColor = page.locator('meta[name="theme-color"]'); await expect(themeColor).toHaveAttribute('content', '#070A0D'); await expect(page.locator('meta[name="apple-mobile-web-app-capable"]')).toHaveAttribute('content', 'yes'); await expect(page.locator('meta[name="apple-mobile-web-app-title"]')).toHaveAttribute('content', 'Nur Falah'); console.log('✅ PWA manifest & meta tags verified'); console.log('\n🎉 FULL HUMAN-LIKE UAT JOURNEY COMPLETE'); console.log('All 6 tabs tested with realistic interactions ✅'); }); });