Files
santifer--career-ops/tests/providers/4dayweek.test.mjs
T
wehub-resource-sync d083df1fdb
CodeQL Analysis / Analyze (javascript-typescript) (push) Failing after 2s
Web CI / web typecheck + build (push) Failing after 1s
Release Please / release-please (push) Failing after 1s
CodeQL Analysis / Analyze (go) (push) Failing after 16s
chore: import upstream snapshot with attribution
2026-07-13 12:02:43 +08:00

162 lines
8.4 KiB
JavaScript

// tests/providers/4dayweek.test.mjs — renamed from fourdayweek.test.mjs to match
// the provider id, so `--only providers/4dayweek` discovers it (#1657).
import { pass, fail, ROOT } from '../helpers.mjs';
import { join } from 'path';
import { pathToFileURL } from 'url';
console.log('\nProvider — 4dayweek');
try {
const fdwModule = await import(pathToFileURL(join(ROOT, 'providers/4dayweek.mjs')).href);
const { resolveProvider } = await import(pathToFileURL(join(ROOT, 'providers/_registry.mjs')).href);
const fourdayweek = fdwModule.default;
const { normalize4dwJob } = fdwModule;
if (fourdayweek.id === '4dayweek') pass('4dayweek.id is "4dayweek"');
else fail(`4dayweek.id is ${JSON.stringify(fourdayweek.id)}`);
const explicitHit = fourdayweek.detect({ name: '4 Day Week', provider: '4dayweek' });
if (explicitHit?.url === 'https://4dayweek.io/api/jobs') {
pass('4dayweek.detect() claims explicit provider config');
} else {
fail(`4dayweek.detect() explicit provider = ${JSON.stringify(explicitHit)}`);
}
const careersHit = fourdayweek.detect({ name: '4 Day Week', careers_url: 'https://4dayweek.io/jobs' });
const apiHit = fourdayweek.detect({ name: '4 Day Week', api: 'https://4dayweek.io/api/jobs' });
if (careersHit?.url === 'https://4dayweek.io/api/jobs' && apiHit?.url === 'https://4dayweek.io/api/jobs') {
pass('4dayweek.detect() maps trusted 4dayweek.io URLs to the feed URL');
} else {
fail(`4dayweek.detect() trusted URLs = ${JSON.stringify({ careersHit, apiHit })}`);
}
const detectMisses = [
fourdayweek.detect({ name: 'X' }),
fourdayweek.detect({ name: 'Other', provider: 'echojobs', careers_url: 'https://4dayweek.io/jobs' }),
fourdayweek.detect({ name: 'Path spoof', careers_url: 'https://evil.example/4dayweek.io/jobs' }),
fourdayweek.detect({ name: 'Suffix spoof', careers_url: 'https://4dayweek.io.evil.example/jobs' }),
fourdayweek.detect({ name: 'HTTP', careers_url: 'http://4dayweek.io/jobs' }),
fourdayweek.detect({ name: 'Non-string', careers_url: 42 }),
];
if (detectMisses.every(hit => hit === null)) {
pass('4dayweek.detect() rejects missing, other-provider, spoofed, http, and non-string URLs');
} else {
fail(`4dayweek.detect() misses = ${JSON.stringify(detectMisses)}`);
}
const resolved = resolveProvider(
{ name: '4 Day Week', careers_url: 'https://4dayweek.io/jobs' },
new Map([['4dayweek', fourdayweek]]),
);
if (resolved && 'provider' in resolved && resolved.provider === fourdayweek) {
pass('provider registry dispatches 4dayweek.detect() for trusted 4dayweek.io URLs');
} else {
fail(`provider registry did not dispatch 4dayweek.detect(): ${JSON.stringify(resolved)}`);
}
// normalize4dwJob — full mapping (url is BUILT from slug; feed has no url).
const full = normalize4dwJob(
{ title: ' Financial Controller ', slug: 'financial-controller-at-panzerglass-45369c18', company_name: ' PanzerGlass ', locations: [{ city: 'Hinnerup', country: 'Denmark' }], work_arrangement: 'onsite', posted: 1782731975, is_expired: false },
'Fallback',
);
if (full && full.title === 'Financial Controller'
&& full.url === 'https://4dayweek.io/job/financial-controller-at-panzerglass-45369c18'
&& full.company === 'PanzerGlass' && full.location === 'Hinnerup, Denmark'
&& full.postedAt === 1782731975 * 1000) {
pass('normalize4dwJob maps title, builds /job/<slug> url, company_name, location, posted(seconds)→ms');
} else {
fail(`normalize4dwJob full row = ${JSON.stringify(full)}`);
}
// work_arrangement: remote → "Remote" appended.
const remoteJob = normalize4dwJob({ title: 'R', slug: 'r-1', locations: [{ city: 'Berlin', country: 'Germany' }], work_arrangement: 'remote' });
if (remoteJob?.location === 'Berlin, Germany, Remote') pass('normalize4dwJob appends "Remote" when work_arrangement is "remote"');
else fail(`normalize4dwJob remote location = ${JSON.stringify(remoteJob?.location)}`);
// company fallbacks: company.name → entry name → "4 Day Week" (whitespace-only ignored).
const coNested = normalize4dwJob({ title: 'T', slug: 's-1', company: { name: 'Nested Co' } });
const coEntry = normalize4dwJob({ title: 'T', slug: 's-2' }, 'Entry Name');
const coDefault = normalize4dwJob({ title: 'T', slug: 's-3' });
const coBlank = normalize4dwJob({ title: 'T', slug: 's-4' }, ' ');
if (coNested?.company === 'Nested Co' && coEntry?.company === 'Entry Name'
&& coDefault?.company === '4 Day Week' && coBlank?.company === '4 Day Week') {
pass('normalize4dwJob falls back company → company.name → entry name → "4 Day Week" (whitespace-only ignored)');
} else {
fail(`normalize4dwJob company fallbacks = ${JSON.stringify({ n: coNested?.company, e: coEntry?.company, d: coDefault?.company, b: coBlank?.company })}`);
}
// postedAt omitted when posted is absent / non-finite.
const noDate = normalize4dwJob({ title: 'T', slug: 's-5' });
const nanDate = normalize4dwJob({ title: 'T', slug: 's-6', posted: 'oops' });
if (noDate && !('postedAt' in noDate) && nanDate && !('postedAt' in nanDate)) {
pass('normalize4dwJob omits postedAt when posted is absent or non-numeric (NaN-safe)');
} else {
fail(`normalize4dwJob date handling = ${JSON.stringify({ none: noDate, nan: nanDate })}`);
}
// drops: expired, empty title, missing/unsafe slug, non-object.
const drops = [
normalize4dwJob({ title: 'Expired', slug: 'x-1', is_expired: true }),
normalize4dwJob({ title: '', slug: 'x-2' }),
normalize4dwJob({ title: 'No slug' }),
normalize4dwJob({ title: 'Unsafe slug', slug: 'a/b' }),
normalize4dwJob({ title: 'Spacey slug', slug: 'a b' }),
normalize4dwJob(null),
];
if (drops.every(r => r === null)) {
pass('normalize4dwJob drops expired / empty-title / no-slug / unsafe-slug / non-object');
} else {
fail(`normalize4dwJob drops = ${JSON.stringify(drops)}`);
}
// fetch(): pagination by ?page=N, stop on has_more:false.
const mk = (i) => ({ title: `Role ${i}`, slug: `role-${i}`, company_name: `Co ${i}`, locations: [{ city: 'Lisbon', country: 'Portugal' }], posted: 1782731975 + i, is_expired: false });
const page1 = { jobs: Array.from({ length: 25 }, (_, i) => mk(i)), total: 50, page: 1, has_more: true };
const page2 = { jobs: [mk(25), mk(26), { title: '', slug: 'bad' }], total: 50, page: 2, has_more: false }; // has_more:false → stop; 1 drop
const requested = [];
const pagedFetch = async (url, opts) => {
requested.push({ url, redirect: opts?.redirect });
return Number(new URL(url).searchParams.get('page')) === 1 ? page1 : page2;
};
const paged = await fourdayweek.fetch({ name: '4 Day Week' }, { fetchJson: pagedFetch });
if (requested.length === 2
&& requested[0].url === 'https://4dayweek.io/api/jobs?page=1'
&& requested[1].url === 'https://4dayweek.io/api/jobs?page=2') {
pass('4dayweek.fetch() builds ?page=N URLs and stops when has_more is false');
} else {
fail(`4dayweek.fetch() requested = ${JSON.stringify(requested.map(r => r.url))}`);
}
if (requested.every(r => r.redirect === 'error')) pass('4dayweek.fetch() passes redirect:"error" on every page (SSRF guard)');
else fail(`4dayweek.fetch() redirect opts = ${JSON.stringify(requested.map(r => r.redirect))}`);
if (paged.length === 27) pass('4dayweek.fetch() aggregates valid jobs across pages (25 + 2, dropping the empty-title row)');
else fail(`4dayweek.fetch() returned ${paged.length} jobs (expected 27)`);
// max_pages cap: only the first page is requested even though has_more is true.
const capReq = [];
await fourdayweek.fetch(
{ name: '4 Day Week', max_pages: 1 },
{ fetchJson: async (url) => { capReq.push(url); return { jobs: Array.from({ length: 25 }, (_, i) => mk(i)), total: 999, has_more: true }; } },
);
if (capReq.length === 1 && capReq[0] === 'https://4dayweek.io/api/jobs?page=1') {
pass('4dayweek.fetch() honors max_pages (stops at the cap even when has_more is true)');
} else {
fail(`4dayweek.fetch() max_pages:1 requested ${JSON.stringify(capReq)}`);
}
// unexpected API response → throws.
let badThrew = false;
try {
await fourdayweek.fetch({ name: 'X' }, { fetchJson: async () => ([]) });
} catch (e) {
badThrew = /unexpected API response/.test(e.message);
}
if (badThrew) pass('4dayweek.fetch() throws on unexpected API response shape (no jobs array)');
else fail('4dayweek.fetch() should throw when the jobs array is absent');
} catch (e) {
fail(`4dayweek provider tests crashed: ${e.message}`);
}