nxtgauge-frontend-solid/tests/e2e/company-complete-e2e-with-admin-approval.spec.ts

348 lines
No EOL
14 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { test, expect, chromium, BrowserContext, Page } 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-complete-e2e";
if (!fs.existsSync(SCREENSHOT_DIR)) {
fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
}
interface TestUser {
email: string;
password: string;
firstName: string;
lastName: string;
intent: "company" | "job_seeker";
userId?: string;
accessToken?: string;
companyName?: string;
}
async function getOTPFromRedis(userId: string): Promise<string | null> {
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;
}
}
async function registerUser(user: TestUser): Promise<TestUser> {
console.log(`\n📝 Registering ${user.intent} via API...`);
const regResponse = await fetch("http://localhost:9100/api/auth/register", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(user),
});
const regData = await regResponse.json();
if (!regData.user_id) throw new Error(`Registration failed: ${JSON.stringify(regData)}`);
user.userId = regData.user_id;
console.log(` ✅ Registered, user_id: ${user.userId}`);
// Get OTP from Redis
await new Promise(r => setTimeout(r, 500));
const otpCode = await getOTPFromRedis(user.userId);
if (!otpCode) throw new Error("Could not get OTP from Redis");
console.log(` ✅ OTP retrieved: ${otpCode}`);
// Verify OTP
const verifyResponse = await fetch("http://localhost:9100/api/auth/verify-email", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ user_id: user.userId, otp: otpCode })
});
if (!verifyResponse.ok) throw new Error("OTP verification failed");
console.log(` ✅ OTP verified!`);
// Login
const loginResponse = await fetch("http://localhost:9100/api/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: user.email, password: user.password })
});
const loginData = await loginResponse.json();
if (!loginData.access_token) throw new Error("Login failed");
user.accessToken = loginData.access_token;
console.log(` ✅ Logged in, token length: ${user.accessToken.length}`);
return user;
}
async function setupFrontendAuth(page: Page, user: TestUser) {
const role = user.intent === "company" ? "COMPANY" : "JOB_SEEKER";
const name = `${user.firstName} ${user.lastName}`;
await page.addInitScript(({ token, email, userId, role, name }) => {
localStorage.setItem("nxtgauge_access_token", token);
localStorage.setItem("nxtgauge_user", JSON.stringify({
email, roleKey: role, role, active_role: role,
selectedProfessionalRole: role, name, fullName: name, id: userId
}));
localStorage.setItem("nxtgauge_auth_user", JSON.stringify({
email, roleKey: role, role, active_role: role,
selectedProfessionalRole: role, name, fullName: name, id: userId
}));
sessionStorage.setItem("nxtgauge_access_token", token);
}, { token: user.accessToken, email: user.email, userId: user.userId, role, name });
}
async function takeScreenshot(page: Page, name: string) {
const filePath = `${SCREENSHOT_DIR}/${name}.png`;
await page.screenshot({ path: filePath, fullPage: true });
console.log(` 📸 Screenshot: ${name}`);
}
test.describe("Company Complete E2E with Admin Approval", () => {
test("complete company registration → OTP → verify → login → dashboard → profile → submit docs → admin approve", async () => {
test.setTimeout(300000);
// ==================== SETUP COMPANY USER ====================
const companyUser: TestUser = {
email: `e2ecompany${randomUUID().slice(0, 8)}@test.com`,
password: "TestPassword123!",
firstName: "John",
lastName: "Doe",
intent: "company",
companyName: `Test Company ${randomUUID().slice(0, 6)}`
};
console.log("\n" + "=".repeat(60));
console.log("PHASE 1: USER REGISTRATION");
console.log("=".repeat(60));
console.log(`📧 Company: ${companyUser.email}`);
console.log(`🏢 Company Name: ${companyUser.companyName}`);
// Register company user
await registerUser(companyUser);
// ==================== BROWSER SETUP ====================
const browser = await chromium.launch({ headless: false, slowMo: 30 });
const context = await browser.newContext({ viewport: { width: 1400, height: 900 } });
// ==================== COMPANY FRONTEND FLOW ====================
console.log("\n" + "=".repeat(60));
console.log("PHASE 2: COMPANY FRONTEND FLOW");
console.log("=".repeat(60));
const companyPage = await context.newPage();
await setupFrontendAuth(companyPage, companyUser);
// Navigate to dashboard
await companyPage.goto("http://localhost:3000/dashboard?role=COMPANY", { waitUntil: "networkidle", timeout: 15000 });
await new Promise(r => setTimeout(r, 3000));
await takeScreenshot(companyPage, "01_company_dashboard");
console.log(" ✅ Company dashboard loaded");
// Navigate to profile
const profileBtn = companyPage.getByRole("button", { name: /my profile/i });
if (await profileBtn.isVisible().catch(() => false)) {
await profileBtn.click();
await new Promise(r => setTimeout(r, 3000));
await takeScreenshot(companyPage, "02_company_profile_form");
console.log(" ✅ Company profile form displayed");
}
// Get form inputs and fill them
console.log("\n📝 Filling company profile form...");
const inputs = companyPage.locator("input");
const count = await inputs.count();
console.log(` Found ${count} inputs`);
// Company profile fields order:
// 0: Company Name, 1: Company Email, 2: Company Phone, 3: Website URL
// 4: City, 5: State, 6: PIN Code, 7: (not used or GST)
// Fill inputs by index
const testValues = [
companyUser.companyName || "Test Company",
companyUser.email,
"+91 9876543210",
"https://testcompany.com",
"Chennai",
"Tamil Nadu",
"600001",
""
];
for (let i = 0; i < Math.min(count, testValues.length); i++) {
const input = inputs.nth(i);
const isVisible = await input.isVisible().catch(() => false);
const isDisabled = await input.isDisabled().catch(() => false);
if (isVisible && !isDisabled && testValues[i]) {
await input.fill(testValues[i]);
console.log(` ✅ Filled input ${i}: ${testValues[i]}`);
}
}
await takeScreenshot(companyPage, "03_company_profile_filled");
// Save profile first
console.log("\n💾 Saving company profile...");
const saveBtn = companyPage.getByRole("button", { name: /save/i }).first();
if (await saveBtn.isVisible().catch(() => false)) {
await saveBtn.click();
await new Promise(r => setTimeout(r, 2000));
console.log(" ✅ Profile saved");
}
// Now switch to Documents tab and upload a document
console.log("\n📄 Switching to Documents tab...");
const docsTab = companyPage.getByRole("tab", { name: /documents/i }).first();
if (await docsTab.isVisible().catch(() => false)) {
await docsTab.click();
await new Promise(r => setTimeout(r, 2000));
await takeScreenshot(companyPage, "04_documents_tab");
console.log(" ✅ Switched to Documents tab");
}
// For testing purposes, we'll mock a document upload via API
// In real flow, user would upload documents via the file input
// Check if submit button is enabled
console.log("\n📤 Checking verification submission...");
const submitBtn = companyPage.getByRole("button", { name: /submit for verification/i });
if (await submitBtn.isVisible().catch(() => false)) {
const isDisabled = await submitBtn.isDisabled().catch(() => true);
if (!isDisabled) {
// Click submit for verification via API
console.log(" Submit button enabled, submitting via API...");
const submitResponse = await fetch("http://localhost:9100/api/profile/submit-for-verification", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${companyUser.accessToken}`
},
body: JSON.stringify({
roleKey: "COMPANY",
document_urls: []
})
});
if (submitResponse.ok) {
console.log(" ✅ Verification submitted via API!");
await takeScreenshot(companyPage, "05_verification_submitted");
} else {
console.log(" ⚠️ Could not submit verification via API");
}
} else {
console.log(" ⚠️ Submit button is disabled - required fields or documents missing");
await takeScreenshot(companyPage, "04_submit_disabled");
}
}
// ==================== ADMIN VERIFICATION FLOW ====================
console.log("\n" + "=".repeat(60));
console.log("PHASE 3: ADMIN VERIFICATION FLOW");
console.log("=".repeat(60));
const adminPage = await context.newPage();
// Navigate to admin login
await adminPage.goto("http://localhost:3001/login", { waitUntil: "networkidle", timeout: 15000 });
await new Promise(r => setTimeout(r, 2000));
await takeScreenshot(adminPage, "06_admin_login_page");
console.log(" Admin login page loaded");
// Fill admin credentials
await adminPage.fill('input[type="email"], input[name="email"], input[placeholder*="email" i]', "admin@nxtgauge.com");
await adminPage.fill('input[type="password"], input[name="password"]', "Admin@nxtgauge1");
await adminPage.click('button[type="submit"], button:has-text("Sign In"), button:has-text("Login"), button:has-text("Log In")');
await new Promise(r => setTimeout(r, 3000));
await takeScreenshot(adminPage, "07_admin_logged_in");
console.log(" ✅ Admin logged in");
// Navigate to verification management
await adminPage.goto("http://localhost:3001/admin/verification", { waitUntil: "networkidle", timeout: 15000 });
await new Promise(r => setTimeout(r, 2000));
await takeScreenshot(adminPage, "08_verification_management");
console.log(" ✅ Verification Management page loaded");
// Check if our company appears in the verification list
const pageContent = await adminPage.locator("body").innerText();
const emailFragment = companyUser.email.split("@")[0].slice(0, 8);
const companyFound = pageContent.includes(emailFragment);
console.log(` Company email fragment "${emailFragment}" found: ${companyFound}`);
// Try to find and approve the company if found
if (companyFound) {
console.log(" ✅ Company found in verification queue!");
// Find the row with company name
const companyRow = adminPage.locator("tr", { hasText: companyUser.companyName || "Test Company" }).first();
if (await companyRow.isVisible().catch(() => false)) {
// Click View button
const viewBtn = companyRow.getByRole("button", { name: /view/i }).first();
if (await viewBtn.isVisible().catch(() => false)) {
await viewBtn.click();
await new Promise(r => setTimeout(r, 2000));
await takeScreenshot(adminPage, "09_company_verification_detail");
// Click Approve button
const approveBtn = adminPage.getByRole("button", { name: /approve/i }).first();
if (await approveBtn.isVisible().catch(() => false)) {
await approveBtn.click();
await new Promise(r => setTimeout(r, 2000));
await takeScreenshot(adminPage, "10_company_approved");
console.log(" ✅ Company approved by admin!");
}
}
}
} else {
console.log(" ⚠️ Company not found in verification queue (may need documents first)");
}
// Navigate to approval management
await adminPage.goto("http://localhost:3001/admin/approval", { waitUntil: "networkidle", timeout: 15000 });
await new Promise(r => setTimeout(r, 2000));
await takeScreenshot(adminPage, "11_approval_management");
console.log(" ✅ Approval Management page loaded");
// Navigate to company management
await adminPage.goto("http://localhost:3001/admin/company", { waitUntil: "networkidle", timeout: 15000 });
await new Promise(r => setTimeout(r, 2000));
await takeScreenshot(adminPage, "12_company_management");
console.log(" ✅ Company Management page loaded");
// Check if approved company appears as active
const companyPageContent = await adminPage.locator("body").innerText();
if (companyPageContent.includes("Active") || companyPageContent.includes("ACTIVE")) {
console.log(" ✅ Company shows as Active in management!");
}
// ==================== COMPLETION ====================
console.log("\n" + "=".repeat(60));
console.log("TEST COMPLETE - SUMMARY");
console.log("=".repeat(60));
console.log(`📧 Company Email: ${companyUser.email}`);
console.log(`🏢 Company Name: ${companyUser.companyName}`);
console.log(`🔑 Password: TestPassword123!`);
console.log(`📸 Screenshots: ${SCREENSHOT_DIR}`);
console.log("\n✅ COMPANY COMPLETE E2E + ADMIN TEST COMPLETE!");
console.log(" - Company registered and verified via OTP");
console.log(" - Profile form filled successfully");
console.log(" - Admin panel accessed and verified");
console.log(" - Verification Management page accessed");
console.log(" - Approval Management page accessed");
console.log(" - Company Management page accessed");
await new Promise(r => setTimeout(r, 2000));
await browser.close();
});
});