352 lines
12 KiB
JavaScript
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());
|