nxtgauge-frontend-solid/tests/e2e/nxtgauge-e2e-lib.ts

397 lines
14 KiB
TypeScript
Raw Normal View History

import { test, expect, chromium, Page, Browser, BrowserContext } from "@playwright/test";
import { randomUUID } from "crypto";
import * as fs from "fs";
import * as path from "path";
const SCREENSHOT_DIR = "./test-results";
const VIDEO_DIR = "./test-videos";
// Ensure directories exist
if (!fs.existsSync(SCREENSHOT_DIR)) fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
if (!fs.existsSync(VIDEO_DIR)) fs.mkdirSync(VIDEO_DIR, { recursive: true });
export interface TestUser {
email: string;
password: string;
firstName: string;
lastName: string;
intent: string;
userId?: string;
accessToken?: string;
}
export interface CompanyUser extends TestUser {
companyName: string;
}
export interface JobSeekerUser extends TestUser {
education?: string;
skills?: string[];
resumePath?: string;
}
async function generateTestEmail(): Promise<string> {
return `test_${randomUUID().slice(0, 8)}@test.com`;
}
async function apiRegister(user: TestUser): Promise<{ user_id: string }> {
const response = await fetch("http://localhost:9100/api/auth/register", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(user),
});
return response.json();
}
async function apiVerifyOtp(): Promise<boolean> {
const response = await fetch("http://localhost:9100/api/auth/verify-email", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ otp: "123456" }),
});
return response.ok;
}
async function apiLogin(email: string, password: string): Promise<{ access_token: string }> {
const response = await fetch("http://localhost:9100/api/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }),
});
return response.json();
}
async function setRedisOtp(userId: string): Promise<void> {
const { execSync } = await import("child_process");
try {
execSync(`redis-cli SETEX "otp:code:123456" 900 "${userId}"`, { encoding: "utf8" });
} catch (e) {
console.log("⚠️ Could not set OTP in Redis:", e);
}
}
async function takeScreenshot(page: Page, name: string): Promise<void> {
const filePath = path.join(SCREENSHOT_DIR, `${name}.png`);
await page.screenshot({ path: filePath, fullPage: true });
console.log(`📸 Screenshot: ${name}`);
}
export async function registerCompany(): Promise<CompanyUser> {
const email = await generateTestEmail();
const companyName = `Test Company ${randomUUID().slice(0, 6)}`;
const user: TestUser = {
email,
password: "TestPassword123!",
firstName: "John",
lastName: "Doe",
intent: "company",
};
console.log("\n📝 Step 1: Registering company via API...");
const regData = await apiRegister(user);
user.userId = regData.user_id;
console.log(" ✅ Registered, user_id:", regData.user_id);
console.log("\n🔐 Step 2: Setting test OTP in Redis...");
await setRedisOtp(regData.user_id);
console.log(" ✅ Set test OTP: 123456");
console.log("\n✅ Step 3: Verifying OTP via API...");
const verified = await apiVerifyOtp();
if (!verified) throw new Error("OTP verification failed");
console.log(" ✅ OTP verified!");
console.log("\n🔑 Step 4: Logging in via API...");
const loginData = await apiLogin(email, user.password);
user.accessToken = loginData.access_token;
console.log(" ✅ Logged in via API!");
return { ...user, companyName };
}
export async function registerJobSeeker(): Promise<JobSeekerUser> {
const email = await generateTestEmail();
const user: TestUser = {
email,
password: "TestPassword123!",
firstName: "Jane",
lastName: "Smith",
intent: "job_seeker",
};
console.log("\n📝 Step 1: Registering job seeker via API...");
const regData = await apiRegister(user);
user.userId = regData.user_id;
console.log(" ✅ Registered, user_id:", regData.user_id);
console.log("\n🔐 Step 2: Setting test OTP in Redis...");
await setRedisOtp(regData.user_id);
console.log(" ✅ Set test OTP: 123456");
console.log("\n✅ Step 3: Verifying OTP via API...");
const verified = await apiVerifyOtp();
if (!verified) throw new Error("OTP verification failed");
console.log(" ✅ OTP verified!");
console.log("\n🔑 Step 4: Logging in via API...");
const loginData = await apiLogin(email, user.password);
user.accessToken = loginData.access_token;
console.log(" ✅ Logged in via API!");
return user;
}
export async function loginViaBrowser(
context: BrowserContext,
email: string,
password: string
): Promise<Page> {
const page = await context.newPage();
console.log("\n🌐 Opening login page...");
await page.goto("http://localhost:3000/login");
await page.waitForLoadState("networkidle");
await takeScreenshot(page, "01-login-page");
console.log("✍️ Filling login form...");
await page.fill('input[type="email"], input[name="email"]', email);
await page.fill('input[type="password"], input[name="password"]', password);
await takeScreenshot(page, "02-login-filled");
console.log("🔐 Handling CAPTCHA (manual entry required)...");
console.log(" Please enter CAPTCHA in the browser window...");
await page.waitForFunction(
() => {
const btn = document.querySelector(".auth-submit-btn, button[type='submit']");
return btn && !(btn as HTMLButtonElement).disabled;
},
{ timeout: 60000 }
);
await page.click(".auth-submit-btn, button[type='submit']");
await page.waitForTimeout(3000);
await takeScreenshot(page, "03-after-login");
return page;
}
export async function setSessionToken(page: Page, token: string): Promise<void> {
await page.evaluate(
(t) => {
window.sessionStorage.setItem("nxtgauge_access_token", t);
window.sessionStorage.setItem("nxtgauge_frontend_access_token", t);
},
token
);
console.log(" ✅ Session token set");
}
export async function navigateToDashboard(page: Page, role?: string): Promise<void> {
const url = role
? `http://localhost:3000/dashboard?role=${role}`
: "http://localhost:3000/dashboard";
await page.goto(url);
await page.waitForLoadState("networkidle");
await page.waitForTimeout(2000);
await takeScreenshot(page, "04-dashboard");
console.log(" ✅ Navigated to dashboard");
}
export async function fillCompanyProfile(page: Page, companyName: string): Promise<void> {
console.log("\n🏢 Filling company profile...");
await page.goto("http://localhost:3000/dashboard/profile?role=COMPANY");
await page.waitForLoadState("networkidle");
await page.waitForTimeout(2000);
await takeScreenshot(page, "05-company-profile");
const nameInput = await page.locator('input[name="companyName"], input[name="name"]').first();
if (await nameInput.isVisible().catch(() => false)) {
await nameInput.fill(companyName);
console.log(" ✅ Company name filled");
}
const websiteInput = await page.locator('input[name="website"], input[placeholder*="website"]').first();
if (await websiteInput.isVisible().catch(() => false)) {
await websiteInput.fill("https://testcompany.com");
console.log(" ✅ Website filled");
}
const phoneInput = await page.locator('input[name="phone"], input[name="companyPhone"]').first();
if (await phoneInput.isVisible().catch(() => false)) {
await phoneInput.fill("+91 9876543210");
console.log(" ✅ Phone filled");
}
await takeScreenshot(page, "06-company-profile-filled");
const submitBtn = await page.locator('button[type="submit"], button:has-text("Submit")').first();
if (await submitBtn.isVisible().catch(() => false)) {
await submitBtn.click();
await page.waitForTimeout(3000);
console.log(" ✅ Profile submitted");
await takeScreenshot(page, "07-company-profile-submitted");
}
}
export async function fillJobSeekerProfile(page: Page): Promise<void> {
console.log("\n👤 Filling job seeker profile...");
await page.goto("http://localhost:3000/dashboard/profile?role=JOB_SEEKER");
await page.waitForLoadState("networkidle");
await page.waitForTimeout(2000);
await takeScreenshot(page, "08-jobseeker-profile");
const firstNameInput = await page.locator('input[name="firstName"], input[name="first_name"]').first();
if (await firstNameInput.isVisible().catch(() => false)) {
await firstNameInput.fill("Jane");
console.log(" ✅ First name filled");
}
const lastNameInput = await page.locator('input[name="lastName"], input[name="last_name"]').first();
if (await lastNameInput.isVisible().catch(() => false)) {
await lastNameInput.fill("Smith");
console.log(" ✅ Last name filled");
}
const bioInput = await page.locator('textarea[name="bio"], textarea[name="about"]').first();
if (await bioInput.isVisible().catch(() => false)) {
await bioInput.fill("Experienced software developer with 5+ years in the industry.");
console.log(" ✅ Bio filled");
}
await takeScreenshot(page, "09-jobseeker-profile-filled");
const submitBtn = await page.locator('button[type="submit"], button:has-text("Submit")').first();
if (await submitBtn.isVisible().catch(() => false)) {
await submitBtn.click();
await page.waitForTimeout(3000);
console.log(" ✅ Profile submitted");
await takeScreenshot(page, "10-jobseeker-profile-submitted");
}
}
export async function adminLogin(context: BrowserContext): Promise<Page> {
console.log("\n🔐 Opening admin panel...");
const adminPage = await context.newPage();
await adminPage.goto("http://localhost:3001/login");
await adminPage.waitForLoadState("networkidle");
await takeScreenshot(adminPage, "11-admin-login");
console.log("✍️ Filling admin credentials...");
await adminPage.fill('input[type="email"], input[name="email"]', "admin@nxtgauge.com");
await adminPage.fill('input[type="password"], input[name="password"]', "Admin@nxtgauge1");
await adminPage.click('button[type="submit"], button:has-text("Login"), button:has-text("Sign In")');
await adminPage.waitForTimeout(3000);
await takeScreenshot(adminPage, "12-admin-dashboard");
console.log(" ✅ Admin logged in");
return adminPage;
}
export async function findUserInAdminVerification(
adminPage: Page,
email: string
): Promise<boolean> {
console.log(`\n🔍 Searching for ${email} in admin verification...`);
const verificationLinks = [
"text=Verifications",
'a:has-text("Verifications")',
'[href*="verification"]',
"text=Pending",
];
for (const selector of verificationLinks) {
const link = adminPage.locator(selector).first();
if (await link.isVisible().catch(() => false)) {
await link.click();
await adminPage.waitForTimeout(2000);
break;
}
}
await takeScreenshot(adminPage, "13-verification-list");
const searchInput = adminPage.locator('input[placeholder*="search" i], input[name="search"]').first();
if (await searchInput.isVisible().catch(() => false)) {
await searchInput.fill(email);
await adminPage.waitForTimeout(2000);
await takeScreenshot(adminPage, "14-search-results");
}
const content = await adminPage.locator("body").innerText();
return content.includes(email);
}
test.describe("Nxtgauge E2E Verification Flows", () => {
test.setTimeout(600000);
test("Company Registration → Profile → Admin Verification", async () => {
const browser = await chromium.launch({ headless: false, slowMo: 100 });
const context = await browser.newContext({
viewport: { width: 1400, height: 900 },
recordVideo: { dir: VIDEO_DIR, size: { width: 1400, height: 900 } },
});
try {
const company = await registerCompany();
console.log("\n🌐 MANUAL STEP: Open browser and:");
console.log(" 1. Go to http://localhost:3000/login");
console.log(" 2. Login with:");
console.log(" Email:", company.email);
console.log(" Password:", company.password);
console.log(" 3. Complete CAPTCHA");
console.log(" 4. Fill company profile at /dashboard/profile?role=COMPANY");
console.log(" 5. Upload business documents");
console.log(" 6. Submit for verification");
console.log(" Then press Enter to continue to admin verification...");
await context.close();
await browser.close();
console.log("\n⏳ Waiting 120 seconds for manual browser steps...");
await new Promise((r) => setTimeout(r, 120000));
} catch (error) {
console.error("❌ Test failed:", error);
throw error;
}
});
test("Job Seeker Registration → Profile → Admin Verification", async () => {
const browser = await chromium.launch({ headless: false, slowMo: 100 });
const context = await browser.newContext({
viewport: { width: 1400, height: 900 },
recordVideo: { dir: VIDEO_DIR, size: { width: 1400, height: 900 } },
});
try {
const jobSeeker = await registerJobSeeker();
console.log("\n🌐 MANUAL STEP: Open browser and:");
console.log(" 1. Go to http://localhost:3000/login");
console.log(" 2. Login with:");
console.log(" Email:", jobSeeker.email);
console.log(" Password:", jobSeeker.password);
console.log(" 3. Complete CAPTCHA");
console.log(" 4. Fill job seeker profile at /dashboard/profile?role=JOB_SEEKER");
console.log(" 5. Add education, skills, resume");
console.log(" 6. Submit for verification");
console.log(" Then press Enter to continue to admin verification...");
await context.close();
await browser.close();
console.log("\n⏳ Waiting 120 seconds for manual browser steps...");
await new Promise((r) => setTimeout(r, 120000));
} catch (error) {
console.error("❌ Test failed:", error);
throw error;
}
});
});