import { test, expect, chromium } from "@playwright/test"; import { randomUUID } from "crypto"; import { execSync } from "child_process"; import * as fs from "fs"; const SCREENSHOT_DIR = "/Users/ashwin/workspace/nxtgauge-frontend-solid/test-results/company-e2e"; if (!fs.existsSync(SCREENSHOT_DIR)) { fs.mkdirSync(SCREENSHOT_DIR, { recursive: true }); } async function getOTPFromRedis(userId: string): Promise { try { const plainKey = `otp:plain:${userId}`; let otpCode = execSync(`redis-cli GET "${plainKey}"`, { encoding: "utf8" }).trim(); if (otpCode && otpCode.length >= 4) return otpCode; const keys = execSync("redis-cli KEYS 'otp:code:*'", { encoding: "utf8" }) .trim().split("\n").filter(Boolean); for (const k of keys) { const v = execSync(`redis-cli GET "${k}"`, { encoding: "utf8" }).trim(); if (v === userId) { otpCode = k.replace("otp:code:", ""); return otpCode; } } return null; } catch { return null; } } test.describe("Company E2E Full Flow", () => { test("complete company registration → OTP → login → dashboard → profile → verification", async () => { const testEmail = `e2ecompany${randomUUID().slice(0, 8)}@test.com`; const testPassword = "TestPassword123!"; const testCompanyName = `Test Company ${randomUUID().slice(0, 6)}`; console.log("📧 Email:", testEmail); console.log("🏢 Company:", testCompanyName); const browser = await chromium.launch({ headless: false, slowMo: 30 }); const context = await browser.newContext({ viewport: { width: 1400, height: 900 } }); // ==================== STEP 1: REGISTER VIA API ==================== console.log("\n📝 STEP 1: Register via API"); let regData: any; try { const regResponse = await fetch("http://localhost:9100/api/auth/register", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: testEmail, first_name: "John", last_name: "Doe", password: testPassword, intent: "company" }) }); regData = await regResponse.json(); expect(regData.user_id).toBeTruthy(); console.log(" ✅ PASS: Registration successful, user_id:", regData.user_id); } catch (e: any) { console.log(" ❌ FAIL: Registration failed -", e.message); throw e; } // ==================== STEP 2: OTP VIA REDIS ==================== console.log("\n🔐 STEP 2: OTP via Redis"); await new Promise(r => setTimeout(r, 500)); let otpCode: string | null = null; try { otpCode = await getOTPFromRedis(regData.user_id); expect(otpCode).toBeTruthy(); console.log(" ✅ PASS: OTP retrieved from Redis:", otpCode); } catch (e: any) { console.log(" ❌ FAIL: Could not get OTP -", e.message); throw e; } // ==================== STEP 3: VERIFY OTP VIA API ==================== console.log("\n✅ STEP 3: Verify OTP via API"); try { const verifyResponse = await fetch("http://localhost:9100/api/auth/verify-email", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ user_id: regData.user_id, otp: otpCode }) }); const verifyData = await verifyResponse.json(); expect(verifyResponse.ok).toBe(true); console.log(" ✅ PASS: OTP verified! Response:", JSON.stringify(verifyData)); } catch (e: any) { console.log(" ❌ FAIL: OTP verification failed -", e.message); throw e; } // ==================== STEP 4: LOGIN VIA API ==================== console.log("\n🔑 STEP 4: Login via API"); let accessToken = ""; try { const loginResponse = await fetch("http://localhost:9100/api/auth/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: testEmail, password: testPassword }) }); const loginData = await loginResponse.json(); accessToken = loginData.access_token || ""; expect(accessToken).toBeTruthy(); console.log(" ✅ PASS: Login successful, token length:", accessToken.length); } catch (e: any) { console.log(" ❌ FAIL: Login failed -", e.message); throw e; } // ==================== STEP 5: DASHBOARD ==================== console.log("\n🌐 STEP 5: Navigate to dashboard?role=COMPANY"); const page = await context.newPage(); // Set auth via addInitScript BEFORE any navigation await page.addInitScript(({ token, email, userId }) => { localStorage.setItem("nxtgauge_access_token", token); localStorage.setItem("nxtgauge_user", JSON.stringify({ email, roleKey: "COMPANY", role: "COMPANY", active_role: "COMPANY", selectedProfessionalRole: "COMPANY", name: "John Doe", fullName: "John Doe", id: userId })); localStorage.setItem("nxtgauge_auth_user", JSON.stringify({ email, roleKey: "COMPANY", role: "COMPANY", active_role: "COMPANY", selectedProfessionalRole: "COMPANY", name: "John Doe", fullName: "John Doe", id: userId })); sessionStorage.setItem("nxtgauge_access_token", token); }, { token: accessToken, email: testEmail, userId: regData.user_id }); try { await page.goto("http://localhost:3000/dashboard?role=COMPANY", { waitUntil: "networkidle", timeout: 15000 }); await page.waitForTimeout(3000); await page.screenshot({ path: `${SCREENSHOT_DIR}/step05_dashboard.png`, fullPage: true }); console.log(" ✅ PASS: Dashboard loaded"); } catch (e: any) { console.log(" ❌ FAIL: Dashboard load failed -", e.message); await page.screenshot({ path: `${SCREENSHOT_DIR}/step05_dashboard_FAIL.png`, fullPage: true }); throw e; } // ==================== STEP 6: PROFILE FORM ==================== console.log("\n📋 STEP 6: Navigate to profile form (click 'My Profile')"); try { const profileBtn = page.getByRole("button", { name: /my profile/i }); const isVisible = await profileBtn.isVisible().catch(() => false); if (isVisible) { await profileBtn.click(); await page.waitForTimeout(3000); } else { console.log(" ⚠️ My Profile button not visible"); } await page.screenshot({ path: `${SCREENSHOT_DIR}/step06_profile_form.png`, fullPage: true }); console.log(" ✅ PASS: Profile form displayed"); } catch (e: any) { console.log(" ⚠️ WARN: Profile navigation -", e.message); await page.screenshot({ path: `${SCREENSHOT_DIR}/step06_profile_form.png`, fullPage: true }); } // ==================== STEP 6B: FILL PROFILE FORM ==================== console.log("\n📝 STEP 6b: Fill company profile fields"); try { // Company profile fields: company_name, company_email, location, state, address // Use more flexible selectors - look for inputs by their associated labels const inputs = page.locator("input"); const count = await inputs.count(); console.log(" Total inputs found:", count); // Try filling first few inputs (likely company_name, company_email, etc.) for (let i = 0; i < Math.min(count, 8); i++) { const input = inputs.nth(i); const isVisible = await input.isVisible().catch(() => false); const isDisabled = await input.isDisabled().catch(() => false); if (isVisible && !isDisabled) { const placeholder = await input.getAttribute("placeholder").catch(() => ""); const id = await input.getAttribute("id").catch(() => ""); const name = await input.getAttribute("name").catch(() => ""); console.log(` Input ${i}: placeholder="${placeholder}" id="${id}" name="${name}"`); } } // Company Name - find by label association const companyNameInput = page.locator("input").filter({ hasText: "" }).first(); if (await companyNameInput.isVisible().catch(() => false)) { await companyNameInput.fill(testCompanyName); console.log(" ✅ Filled company name"); } // Try finding by label text const labels = await page.locator("label").all(); for (const label of labels) { const text = await label.textContent().catch(() => ""); console.log(" Label:", text); } await page.screenshot({ path: `${SCREENSHOT_DIR}/step06b_profile_inputs.png`, fullPage: true }); console.log(" ✅ Profile form analyzed"); } catch (e: any) { console.log(" ⚠️ WARN: Could not fill profile -", e.message); await page.screenshot({ path: `${SCREENSHOT_DIR}/step06b_profile_fill_FAIL.png`, fullPage: true }); } // ==================== STEP 7: SUBMIT VERIFICATION ==================== console.log("\n📤 STEP 7: Submit verification"); try { const submitBtn = page.getByRole("button", { name: /submit for verification/i }); const btnVisible = await submitBtn.isVisible().catch(() => false); if (btnVisible) { const isDisabled = await submitBtn.isDisabled().catch(() => true); if (isDisabled) { console.log(" ⚠️ INFO: Submit button disabled - profile needs fields filled"); await page.screenshot({ path: `${SCREENSHOT_DIR}/step07_submit_disabled.png`, fullPage: true }); // Try Documents tab const docsTab = page.getByRole("tab", { name: /documents/i }).first(); if (await docsTab.isVisible().catch(() => false)) { await docsTab.click(); await page.waitForTimeout(2000); await page.screenshot({ path: `${SCREENSHOT_DIR}/step07_documents_tab.png`, fullPage: true }); console.log(" ✅ Switched to Documents tab"); } } else { await submitBtn.click(); await page.waitForTimeout(3000); await page.screenshot({ path: `${SCREENSHOT_DIR}/step07_verification_submitted.png`, fullPage: true }); console.log(" ✅ PASS: Verification submitted!"); } } else { console.log(" ⚠️ INFO: Submit button not found"); await page.screenshot({ path: `${SCREENSHOT_DIR}/step07_submit_notfound.png`, fullPage: true }); } } catch (e: any) { console.log(" ⚠️ WARN: Verification submit -", e.message); await page.screenshot({ path: `${SCREENSHOT_DIR}/step07_verification_FAIL.png`, fullPage: true }); } await page.screenshot({ path: `${SCREENSHOT_DIR}/step99_final.png`, fullPage: true }); console.log("\n========== TEST COMPLETE =========="); console.log("📸 Screenshots:", SCREENSHOT_DIR); console.log("📧 Test email:", testEmail); console.log("🔑 Password:", testPassword); console.log("🏢 Company:", testCompanyName); await new Promise(r => setTimeout(r, 1000)); await browser.close(); }); });