// @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 }); }); });