// tests/providers/themuse.test.mjs — moved verbatim from test-all.mjs (#1440). import { pass, fail, ROOT } from '../helpers.mjs'; import { join } from 'path'; import { pathToFileURL } from 'url'; console.log('\nProvider — themuse'); try { const museModule = await import(pathToFileURL(join(ROOT, 'providers/themuse.mjs')).href); const themuse = museModule.default; const { normalizeMuseJob } = museModule; if (themuse.id === 'themuse') pass('themuse.id is "themuse"'); else fail(`themuse.id is ${JSON.stringify(themuse.id)}`); // normalizeMuseJob — field mapping const job = normalizeMuseJob({ name: 'Staff AI Engineer', refs: { landing_page: 'https://www.themuse.com/jobs/acme/staff-ai-engineer' }, company: { name: 'Acme Corp' }, locations: [{ name: 'Remote' }], }); if (job?.title === 'Staff AI Engineer') pass('normalizeMuseJob maps name → title'); else fail(`normalizeMuseJob title = ${JSON.stringify(job?.title)}`); if (job?.url === 'https://www.themuse.com/jobs/acme/staff-ai-engineer') pass('normalizeMuseJob maps refs.landing_page → url'); else fail(`normalizeMuseJob url = ${JSON.stringify(job?.url)}`); if (job?.company === 'Acme Corp') pass('normalizeMuseJob maps company.name → company'); else fail(`normalizeMuseJob company = ${JSON.stringify(job?.company)}`); if (job?.location === 'Remote') pass('normalizeMuseJob maps locations[0].name → location'); else fail(`normalizeMuseJob location = ${JSON.stringify(job?.location)}`); // Missing/invalid field handling if (normalizeMuseJob({ name: '', refs: { landing_page: 'https://www.themuse.com/jobs/x' }, company: { name: 'X' }, locations: [] }) === null) pass('normalizeMuseJob drops entries with empty title'); else fail('normalizeMuseJob should return null for empty title'); if (normalizeMuseJob({ name: 'Role', refs: { landing_page: '/relative' }, company: { name: 'X' }, locations: [] }) === null) pass('normalizeMuseJob drops entries with a non-absolute landing_page URL'); else fail('normalizeMuseJob should return null for a relative URL'); const noLoc = normalizeMuseJob({ name: 'Role', refs: { landing_page: 'https://www.themuse.com/jobs/x' }, company: { name: 'X' }, locations: [], }); if (noLoc?.location === '') pass('normalizeMuseJob returns empty location when locations array is empty'); else fail(`normalizeMuseJob location for empty locations = ${JSON.stringify(noLoc?.location)}`); const noCompany = normalizeMuseJob({ name: 'Role', refs: { landing_page: 'https://www.themuse.com/jobs/x' }, company: null, locations: [{ name: 'NYC' }], }); if (noCompany?.company === 'The Muse') pass('normalizeMuseJob falls back to "The Muse" when company.name is missing'); else fail(`normalizeMuseJob company fallback = ${JSON.stringify(noCompany?.company)}`); if (normalizeMuseJob(null) === null && normalizeMuseJob('string') === null) pass('normalizeMuseJob returns null for non-object inputs'); else fail('normalizeMuseJob should return null for null/non-object input'); // fetch() — mock ctx const sampleResults = [ { name: 'Staff AI Engineer', refs: { landing_page: 'https://www.themuse.com/jobs/acme/staff-ai-engineer' }, company: { name: 'Acme Corp' }, locations: [{ name: 'Remote' }], }, { name: 'Platform Engineer', refs: { landing_page: 'https://www.themuse.com/jobs/beta/platform-engineer' }, company: { name: 'Beta Inc' }, locations: [], }, { name: '', refs: { landing_page: 'https://www.themuse.com/jobs/bad/role' }, company: { name: 'Bad Co' }, locations: [], }, ]; let capturedUrl = null; let capturedOpts = null; const fetched = await themuse.fetch( { name: 'The Muse Board', provider: 'themuse' }, { fetchJson: async (url, opts) => { capturedUrl = url; capturedOpts = opts; return { results: sampleResults, page: 0, page_count: 1 }; }, }, ); if (capturedUrl === 'https://www.themuse.com/api/public/jobs?page=0') pass('themuse.fetch() requests the correct API endpoint'); else fail(`themuse.fetch() requested ${JSON.stringify(capturedUrl)}`); if (capturedOpts && capturedOpts.redirect === 'error') pass('themuse.fetch() passes redirect:"error" to fetchJson'); else fail(`themuse.fetch() should pass redirect:"error", got: ${JSON.stringify(capturedOpts)}`); if (fetched.length === 2) pass('themuse.fetch() normalizes 2 valid jobs (drops the empty-title entry)'); else fail(`themuse.fetch() returned ${fetched.length} jobs (expected 2)`); if (fetched[0]?.title === 'Staff AI Engineer' && fetched[0]?.company === 'Acme Corp') pass('themuse.fetch() returns correct title and company for first result'); else fail(`themuse.fetch() row 0 = ${JSON.stringify(fetched[0])}`); // Pagination: page_count > 1 causes all pages to be fetched and aggregated. const paginationCalls = []; const page1Result = { name: 'Data Engineer', refs: { landing_page: 'https://www.themuse.com/jobs/acme/de' }, company: { name: 'Acme' }, locations: [] }; const paginatedJobs = await themuse.fetch( { name: 'The Muse Board', provider: 'themuse' }, { fetchJson: async (url, opts) => { paginationCalls.push(url); const page = parseInt(new URL(url).searchParams.get('page') ?? '0', 10); if (page === 0) return { results: [sampleResults[0]], page: 0, page_count: 2 }; return { results: [page1Result], page: 1, page_count: 2 }; }, }, ); if (paginationCalls.length === 2 && paginationCalls[0] === 'https://www.themuse.com/api/public/jobs?page=0' && paginationCalls[1] === 'https://www.themuse.com/api/public/jobs?page=1') pass('themuse.fetch() iterates all pages when page_count > 1'); else fail(`themuse.fetch() pagination calls = ${JSON.stringify(paginationCalls)}`); if (paginatedJobs.length === 2 && paginatedJobs[1]?.title === 'Data Engineer') pass('themuse.fetch() aggregates results from all pages'); else fail(`themuse.fetch() paginated results = ${JSON.stringify(paginatedJobs.map(j => j.title))}`); // page_count cap: a huge value must be clamped to 100, not cause unbounded requests. let cappedCalls = 0; await themuse.fetch( { name: 'X', provider: 'themuse' }, { fetchJson: async () => { cappedCalls++; return { results: [], page: 0, page_count: 99999 }; } }, ); if (cappedCalls === 100) pass('themuse.fetch() clamps page_count to 100 (prevents unbounded requests)'); else fail(`themuse.fetch() made ${cappedCalls} requests for page_count=99999 (expected 100)`); // Non-integer page_count must be ignored (NaN passes typeof==='number' but not Number.isInteger). let nonIntCalls = 0; await themuse.fetch( { name: 'X', provider: 'themuse' }, { fetchJson: async () => { nonIntCalls++; return { results: [], page: 0, page_count: 1.5 }; } }, ); if (nonIntCalls === 1) pass('themuse.fetch() ignores non-integer page_count (fetches only page 0)'); else fail(`themuse.fetch() made ${nonIntCalls} requests for page_count=1.5 (expected 1)`); let badResponseThrew = false; try { await themuse.fetch( { name: 'X', provider: 'themuse' }, { fetchJson: async () => ({ wrong: true }) }, ); } catch (e) { badResponseThrew = /unexpected API response/.test(e.message); } if (badResponseThrew) pass('themuse.fetch() throws on unexpected API response shape'); else fail('themuse.fetch() should throw when results array is absent'); } catch (e) { fail(`themuse provider tests crashed: ${e.message}`); }