104 lines
3.9 KiB
JavaScript
104 lines
3.9 KiB
JavaScript
// @ts-nocheck
|
|
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 });
|
|
});
|
|
});
|