dev1/tests/e2e/50-resume-rewrite.spec.mjs

104 lines
3.9 KiB
JavaScript

// @ts-check
import { test, expect } from '@playwright/test';
import { loadTestUser } from '../utils/testUser.js';
const j = (o) => JSON.stringify(o);
/** Try common routes until the heading "Resume Optimizer" appears. */
async function gotoResume(page) {
const candidates = [
'/resume-optimizer',
'/tools/resume',
'/premium/resume',
'/resume'
];
for (const path of candidates) {
await page.goto(path, { waitUntil: 'domcontentloaded' }).catch(() => {});
const heading = page.getByRole('heading', { name: /^Resume Optimizer$/i }).first();
if (await heading.count()) return true;
}
return false;
}
test.describe('@p1 ResumeRewrite — upload + optimize (50)', () => {
test.setTimeout(20000);
test('Uploads PDF, fills fields, sees spinner, and shows optimized resume', async ({ page }) => {
const u = loadTestUser();
// Premium/user gate (keeps app happy if it checks)
await page.route(
/\/api\/user-profile\?fields=.*(firstname|is_premium|is_pro_premium).*/i,
r => r.fulfill({
status: 200,
contentType: 'application/json',
body: j({ firstname: 'Tester', is_premium: 1, is_pro_premium: 0 })
})
);
// Remaining optimizations banner
await page.route(/\/api\/premium\/resume\/remaining$/i, r => r.fulfill({
status: 200,
contentType: 'application/json',
body: j({ remainingOptimizations: 3, resetDate: '2026-01-31T00:00:00Z' })
}));
// Optimize endpoint — simulate a short delay and return deterministic text
await page.route(/\/api\/premium\/resume\/optimize$/i, async r => {
await new Promise(res => setTimeout(res, 350)); // small “thinking” delay
return r.fulfill({
status: 200,
contentType: 'application/json',
body: j({
optimizedResume:
`John Q. Dev
— Optimized for Software Engineer —
• Quantified accomplishments aligned to the job description.
• Highlighted skills: JavaScript, React, APIs.
• Keyword-tuned for ATS while keeping clarity.`
})
});
});
// Sign in
await page.context().clearCookies();
await page.goto('/signin', { waitUntil: 'domcontentloaded' });
await page.getByPlaceholder('Username', { exact: true }).fill(u.username);
await page.getByPlaceholder('Password', { exact: true }).fill(u.password);
await page.getByRole('button', { name: /^Sign In$/ }).click();
// Find the Resume Optimizer page (try common routes)
const found = await gotoResume(page);
expect(found).toBeTruthy();
// Banner shows remaining count
await expect(page.getByText(/3.*Resume Optimizations Remaining/i)).toBeVisible({ timeout: 4000 });
await expect(page.getByText(/Resets on/i)).toBeVisible({ timeout: 4000 });
// Upload a tiny in-memory PDF (valid mime & small size)
const pdfBytes = Buffer.from('%PDF-1.4\n%âãÏÓ\n1 0 obj\n<<>>\nendobj\ntrailer\n<<>>\n%%EOF', 'utf-8');
await page.locator('input[type="file"]').setInputFiles({
name: 'resume.pdf',
mimeType: 'application/pdf',
buffer: pdfBytes
});
// Fill Job Title and Job Description
await page.getByPlaceholder(/e\.g\.,?\s*Software Engineer/i).fill('Software Engineer');
await page.getByPlaceholder(/Paste the job listing|requirements here/i)
.fill('We need a JavaScript/React engineer to build customer-facing features.');
// Submit
const submitBtn = page.getByRole('button', { name: /^Optimize Resume$/i });
await submitBtn.click();
// Spinner + disabled button during optimization
await expect(page.getByText(/Optimizing your resume/i)).toBeVisible({ timeout: 2000 });
// Optimized Resume appears, and button re-enables
await expect(page.getByRole('heading', { name: /^Optimized Resume$/i })).toBeVisible({ timeout: 7000 });
await expect(page.locator('pre')).toContainText(/Optimized for Software Engineer/i, { timeout: 7000 });
});
});