JB/web/tests/integration/postgres-e2e.test.js

352 lines
12 KiB
JavaScript

/**
* Real Database E2E Test Suite against live PostgreSQL
* Verifies relational queries, transactions, job posting, applications, and ATS movement
*/
const { PrismaClient } = require("@prisma/client");
const assert = require("assert");
const prisma = new PrismaClient();
async function runE2ETests() {
console.log("=========================================");
console.log(" POSTGRESQL REAL WORKFLOW E2E TESTS ");
console.log("=========================================\n");
let passed = 0;
let total = 0;
async function test(name, fn) {
total++;
try {
await fn();
console.log(` [PASS] ${name}`);
passed++;
} catch (err) {
console.error(` [FAIL] ${name}: ${err.message}`);
}
}
// 1. Database Connectivity & Core Table Queries
await test("PostgreSQL counts match expected baseline", async () => {
const jobCount = await prisma.job.count();
const companyCount = await prisma.company.count();
const userCount = await prisma.user.count();
assert.strictEqual(jobCount, 1425, `Expected 1425 jobs, got ${jobCount}`);
assert.strictEqual(companyCount, 400, `Expected 400 companies, got ${companyCount}`);
assert.ok(userCount >= 9, `Expected at least 9 users, got ${userCount}`);
});
// 2. Organization Isolation: Scraped Job Safeguard
await test("Scraped jobs have no postedById/companyId and cannot be hijacked", async () => {
const scrapedJob = await prisma.job.findFirst({
where: { source: { not: "EMPLOYER_DIRECT" } },
});
assert.ok(scrapedJob, "Scraped job must exist");
assert.strictEqual(scrapedJob.postedById, null, "Scraped job must have null postedById");
assert.strictEqual(scrapedJob.companyId, null, "Scraped job must have null companyId");
});
// 3. Complete Seeker & Employer Lifecycle Transaction
await test("Employer posting job, candidate applying, and employer viewing in ATS", async () => {
const timestamp = Date.now();
const testCompany = await prisma.company.create({
data: {
name: `Acme Corp ${timestamp}`,
location: "Hartford, CT",
description: "Innovative engineering enterprise",
},
});
const employerUser = await prisma.user.create({
data: {
name: "Lead Recruiter",
email: `recruiter_${timestamp}@acme.com`,
passwordHash: "$2b$12$dummyhashforproductione2etesting",
role: "EMPLOYER",
companyId: testCompany.id,
},
});
const seekerUser = await prisma.user.create({
data: {
name: "Jane Candidate",
email: `candidate_${timestamp}@gmail.com`,
passwordHash: "$2b$12$dummyhashforproductione2etesting",
role: "SEEKER",
},
});
// Create Candidate Profile & Resume
const profile = await prisma.userProfile.create({
data: {
userId: seekerUser.id,
headline: "Staff Cloud Systems Architect",
location: "Stamford, CT",
isPublic: true,
searchableToEmployers: true,
},
});
const resume = await prisma.resume.create({
data: {
userId: seekerUser.id,
title: "Principal Cloud Engineer Resume",
data: JSON.stringify({
profile: { headline: "Staff Cloud Systems Architect" },
skills: ["Kubernetes", "PostgreSQL", "Go", "Distributed Systems"],
}),
isActiveForMatching: true,
},
});
// Employer direct job posting
const job = await prisma.job.create({
data: {
jobUrlHash: `hash_${timestamp}`,
title: "Staff Cloud Engineer",
company: testCompany.name,
location: "Hartford, CT",
isRemote: true,
department: "Software & Engineering",
experienceLevel: "Senior",
description: "Architect distributed cloud infrastructure across high-availability clusters.",
salaryMin: 160000,
salaryMax: 210000,
jobUrl: `http://localhost:3000/jobs/cloud-eng-${timestamp}`,
source: "EMPLOYER_DIRECT",
datePosted: new Date(),
postedById: employerUser.id,
companyId: testCompany.id,
},
});
assert.strictEqual(job.postedById, employerUser.id);
assert.strictEqual(job.companyId, testCompany.id);
// Seeker submits application with frozen snapshot
const application = await prisma.application.create({
data: {
jobId: job.id,
applicantId: seekerUser.id,
status: "APPLIED",
coverLetter: "Excited about distributed cloud systems at Acme!",
snapshotJson: JSON.stringify({
applicant: { id: seekerUser.id, name: seekerUser.name, email: seekerUser.email },
resume: { id: resume.id, title: resume.title },
}),
},
});
assert.ok(application.id);
assert.strictEqual(application.status, "APPLIED");
// Employer retrieves ATS candidates strictly scoped to their company
const employerATSQuery = await prisma.application.findMany({
where: {
job: {
OR: [
{ postedById: employerUser.id },
{ companyId: employerUser.companyId },
],
},
},
include: { job: true, applicant: true },
});
assert.strictEqual(employerATSQuery.length, 1);
assert.strictEqual(employerATSQuery[0].applicant.email, seekerUser.email);
// Employer transitions candidate through Kanban stage
const updatedApp = await prisma.application.update({
where: { id: application.id },
data: {
status: "INTERVIEW",
statusHistory: {
create: {
fromStatus: "APPLIED",
toStatus: "INTERVIEW",
changedById: employerUser.id,
note: "Selected for architectural deep-dive interview",
},
},
},
include: { statusHistory: true },
});
assert.strictEqual(updatedApp.status, "INTERVIEW");
assert.strictEqual(updatedApp.statusHistory.length, 1);
assert.strictEqual(updatedApp.statusHistory[0].toStatus, "INTERVIEW");
// Recruiter adds confidential evaluation note
const note = await prisma.candidateNote.create({
data: {
applicationId: application.id,
authorId: employerUser.id,
noteText: "Excellent systems architecture knowledge; offer senior level.",
},
});
assert.ok(note.id);
assert.strictEqual(note.noteText, "Excellent systems architecture knowledge; offer senior level.");
// Cleanup test records
await prisma.candidateNote.delete({ where: { id: note.id } });
await prisma.applicationStatusHistory.deleteMany({ where: { applicationId: application.id } });
await prisma.application.delete({ where: { id: application.id } });
await prisma.job.delete({ where: { id: job.id } });
await prisma.resume.delete({ where: { id: resume.id } });
await prisma.userProfile.delete({ where: { id: profile.id } });
await prisma.user.delete({ where: { id: seekerUser.id } });
await prisma.user.delete({ where: { id: employerUser.id } });
await prisma.company.delete({ where: { id: testCompany.id } });
});
// 4. PostgreSQL Full-Text Search Performance
await test("PostgreSQL title & description search query execution", async () => {
const results = await prisma.job.findMany({
where: {
OR: [
{ title: { contains: "Software" } },
{ description: { contains: "Software" } },
],
},
take: 10,
});
assert.ok(results.length > 0, "Should find jobs matching keyword 'Software'");
});
// 5. Phase 5: Organization Membership & Scoped Permissions in PostgreSQL
await test("PostgreSQL OrganizationMembership creation and role-scoping", async () => {
const ts = Date.now();
const testCompany = await prisma.company.create({
data: {
name: `Org Test Corp ${ts}`,
verificationStatus: "VERIFIED",
verifiedAt: new Date(),
},
});
const ownerUser = await prisma.user.create({
data: {
email: `owner_${ts}@orgtest.com`,
passwordHash: "$2b$12$dummyHashForOwnerOrgTestingOnly123456789",
role: "EMPLOYER",
companyId: testCompany.id,
},
});
const recruiterUser = await prisma.user.create({
data: {
email: `recruiter_${ts}@orgtest.com`,
passwordHash: "$2b$12$dummyHashForRecruiterOrgTestingOnly123",
role: "EMPLOYER",
companyId: testCompany.id,
},
});
// Create scoped memberships
const ownerMembership = await prisma.organizationMembership.create({
data: {
userId: ownerUser.id,
companyId: testCompany.id,
role: "OWNER",
status: "ACTIVE",
},
});
const recruiterMembership = await prisma.organizationMembership.create({
data: {
userId: recruiterUser.id,
companyId: testCompany.id,
role: "RECRUITER",
status: "ACTIVE",
},
});
assert.strictEqual(ownerMembership.role, "OWNER");
assert.strictEqual(recruiterMembership.role, "RECRUITER");
// Clean up
await prisma.organizationMembership.deleteMany({ where: { companyId: testCompany.id } });
await prisma.user.delete({ where: { id: ownerUser.id } });
await prisma.user.delete({ where: { id: recruiterUser.id } });
await prisma.company.delete({ where: { id: testCompany.id } });
});
// 6. Phase 5: Company Claiming & Verification State Transition in PostgreSQL
await test("PostgreSQL CompanyClaim workflow: submission, approval, and verification status change", async () => {
const ts = Date.now();
const publicCompany = await prisma.company.create({
data: {
name: `Public Scraped Corp ${ts}`,
verificationStatus: "UNCLAIMED",
},
});
const claimantUser = await prisma.user.create({
data: {
email: `claimant_${ts}@scrapedcorp.com`,
passwordHash: "$2b$12$dummyHashForClaimantOrgTesting123456789",
role: "EMPLOYER",
},
});
// Submit claim
const claim = await prisma.companyClaim.create({
data: {
companyId: publicCompany.id,
claimantId: claimantUser.id,
corporateEmail: claimantUser.email,
evidenceType: "DOMAIN_MATCH",
evidenceData: "Corporate domain matches website",
status: "PENDING",
},
});
assert.strictEqual(claim.status, "PENDING");
// Admin approves claim -> updates company to VERIFIED and creates OWNER membership
await prisma.$transaction([
prisma.companyClaim.update({
where: { id: claim.id },
data: { status: "APPROVED", reviewedAt: new Date() },
}),
prisma.company.update({
where: { id: publicCompany.id },
data: { verificationStatus: "VERIFIED", verifiedAt: new Date() },
}),
prisma.organizationMembership.create({
data: {
userId: claimantUser.id,
companyId: publicCompany.id,
role: "OWNER",
status: "ACTIVE",
},
}),
]);
const verifiedCompany = await prisma.company.findUnique({ where: { id: publicCompany.id } });
assert.strictEqual(verifiedCompany.verificationStatus, "VERIFIED");
// Clean up
await prisma.organizationMembership.deleteMany({ where: { companyId: publicCompany.id } });
await prisma.companyClaim.delete({ where: { id: claim.id } });
await prisma.user.delete({ where: { id: claimantUser.id } });
await prisma.company.delete({ where: { id: publicCompany.id } });
});
console.log("\n=========================================");
console.log(` E2E RESULTS: ${passed} / ${total} tests passed (${Math.round((passed / total) * 100)}%)`);
console.log("=========================================\n");
if (passed !== total) {
process.exit(1);
}
}
runE2ETests()
.catch((err) => {
console.error("E2E Test execution error:", err);
process.exit(1);
})
.finally(() => prisma.$disconnect());