Files
santifer--career-ops/tests/providers/solidjobs.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

220 lines
10 KiB
JavaScript

// tests/providers/solidjobs.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 — solidjobs');
try {
const sj = (await import(pathToFileURL(join(ROOT, 'providers/solidjobs.mjs')).href)).default;
if (sj.id === 'solidjobs') pass('solidjobs.id is "solidjobs"');
else fail(`solidjobs.id is ${JSON.stringify(sj.id)}`);
// detect() matches valid SolidJobs API URL
const hit = sj.detect({ name: 'SJ', careers_url: 'https://solid.jobs/public-api/offers/it?campaign=career-ops' });
if (hit && hit.url) pass('solidjobs.detect() matches valid API URL');
else fail('solidjobs.detect() should match solid.jobs public-api URL');
// detect() rejects non-SolidJobs URL
if (sj.detect({ name: 'X', careers_url: 'https://example.com/jobs' }) === null) {
pass('solidjobs.detect() rejects non-SolidJobs URL');
} else {
fail('solidjobs.detect() must reject non-SolidJobs URLs');
}
// detect() rejects path-spoofed URL (solid.jobs in path, not hostname)
if (sj.detect({ name: 'X', careers_url: 'https://evil.example/solid.jobs/public-api/offers/it' }) === null) {
pass('solidjobs.detect() rejects path-spoofed URLs');
} else {
fail('solidjobs.detect() must NOT misdetect URLs with solid.jobs in the path');
}
// detect() returns null for non-string careers_url
if (sj.detect({ name: 'X', careers_url: 42 }) === null) {
pass('solidjobs.detect() returns null for non-string careers_url (42)');
} else {
fail('solidjobs.detect() should treat non-string careers_url as missing');
}
// detect() returns null for missing careers_url
if (sj.detect({ name: 'X' }) === null) {
pass('solidjobs.detect() returns null for missing careers_url');
} else {
fail('solidjobs.detect() should return null when careers_url is missing');
}
// fetch() parses { jobs: [...] } response with company from API
const fakeJobs = {
jobs: [
{ title: 'Senior Dev', url: 'https://solid.jobs/o/abc123/career-ops', company: 'Acme Corp', locations: ['Warszawa', 'Remote'] },
{ title: 'Junior Dev', url: 'https://solid.jobs/o/def456/career-ops', company: 'Beta Inc', locations: ['Kraków'] },
],
};
const parsed = await sj.fetch(
{ name: 'SolidJobs IT', careers_url: 'https://solid.jobs/public-api/offers/it?campaign=career-ops' },
{ transport: 'http', fetchJson: async () => fakeJobs, fetchText: async () => '' },
);
if (parsed.length === 2) pass('solidjobs.fetch() returns 2 jobs from mock response');
else fail(`solidjobs.fetch() returned ${parsed.length} jobs, expected 2`);
if (parsed[0].company === 'Acme Corp') pass('solidjobs.fetch() uses j.company from API response');
else fail(`solidjobs.fetch() company is ${JSON.stringify(parsed[0].company)}, expected "Acme Corp"`);
if (parsed[0].location === 'Warszawa, Remote') pass('solidjobs.fetch() joins locations array');
else fail(`solidjobs.fetch() location is ${JSON.stringify(parsed[0].location)}, expected "Warszawa, Remote"`);
if (parsed[0].title === 'Senior Dev' && parsed[0].url === 'https://solid.jobs/o/abc123/career-ops') {
pass('solidjobs.fetch() maps title and url correctly');
} else {
fail(`solidjobs.fetch() title/url wrong: ${JSON.stringify(parsed[0])}`);
}
// fetch() falls back to entry.name when j.company is missing
const noCompanyJobs = { jobs: [{ title: 'Tester', url: 'https://solid.jobs/o/xyz/career-ops', locations: [] }] };
const fallback = await sj.fetch(
{ name: 'SolidJobs IT', careers_url: 'https://solid.jobs/public-api/offers/it?campaign=career-ops' },
{ transport: 'http', fetchJson: async () => noCompanyJobs, fetchText: async () => '' },
);
if (fallback[0].company === 'SolidJobs IT') pass('solidjobs.fetch() falls back to entry.name when j.company missing');
else fail(`solidjobs.fetch() fallback company is ${JSON.stringify(fallback[0].company)}`);
// fetch() handles empty locations array
if (fallback[0].location === '') pass('solidjobs.fetch() returns empty string for empty locations array');
else fail(`solidjobs.fetch() location for empty array is ${JSON.stringify(fallback[0].location)}`);
// fetch() rejects non-SolidJobs hostname (SSRF)
let ssrfRejected = false;
try {
await sj.fetch(
{ name: 'Evil', careers_url: 'https://evil.com/public-api/offers/it' },
{ transport: 'http', fetchJson: async () => { throw new Error('SSRF! should not reach here'); }, fetchText: async () => '' },
);
} catch (e) {
if (e.message.includes('untrusted hostname')) ssrfRejected = true;
else fail(`solidjobs.fetch() rejected with wrong error: ${e.message}`);
}
if (ssrfRejected) pass('solidjobs.fetch() rejects untrusted hostname (SSRF protection)');
else fail('solidjobs.fetch() should reject non-solid.jobs hostnames');
// fetch() throws on missing careers_url
let missingUrl = false;
try {
await sj.fetch(
{ name: 'No URL' },
{ transport: 'http', fetchJson: async () => ({}), fetchText: async () => '' },
);
} catch (e) {
if (e.message.includes('careers_url required')) missingUrl = true;
else fail(`solidjobs.fetch() missing URL error: ${e.message}`);
}
if (missingUrl) pass('solidjobs.fetch() throws on missing careers_url');
else fail('solidjobs.fetch() should throw when careers_url is missing');
// fetch() rejects HTTP (non-HTTPS) URL
let httpRejected = false;
try {
await sj.fetch(
{ name: 'HTTP', careers_url: 'http://solid.jobs/public-api/offers/it' },
{ transport: 'http', fetchJson: async () => { throw new Error('should not reach here'); }, fetchText: async () => '' },
);
} catch (e) {
if (e.message.includes('HTTPS')) httpRejected = true;
else fail(`solidjobs.fetch() HTTP rejection wrong error: ${e.message}`);
}
if (httpRejected) pass('solidjobs.fetch() rejects HTTP URLs (HTTPS enforcement)');
else fail('solidjobs.fetch() should reject non-HTTPS URLs');
// fetch() rejects malformed/unparseable URL
let malformedRejected = false;
try {
await sj.fetch(
{ name: 'Bad', careers_url: 'not-a-url' },
{ transport: 'http', fetchJson: async () => { throw new Error('should not reach here'); }, fetchText: async () => '' },
);
} catch (e) {
if (e.message.includes('invalid URL')) malformedRejected = true;
else fail(`solidjobs.fetch() malformed URL wrong error: ${e.message}`);
}
if (malformedRejected) pass('solidjobs.fetch() rejects malformed URLs');
else fail('solidjobs.fetch() should reject unparseable URLs');
// fetch() throws on unexpected API response (no jobs array)
const badResponses = [
[{}, 'empty object'],
[{ jobs: null }, 'jobs: null'],
[{ jobs: 'not-array' }, 'jobs: string'],
[{ offers: [] }, 'wrong key name'],
[null, 'null response'],
];
for (const [resp, label] of badResponses) {
let threw = false;
try {
await sj.fetch(
{ name: 'SolidJobs IT', careers_url: 'https://solid.jobs/public-api/offers/it?campaign=career-ops' },
{ transport: 'http', fetchJson: async () => resp, fetchText: async () => '' },
);
} catch (e) {
if (e.message.includes('unexpected API response')) threw = true;
else fail(`solidjobs.fetch() bad response (${label}) wrong error: ${e.message}`);
}
if (threw) pass(`solidjobs.fetch() throws on bad API response (${label})`);
else fail(`solidjobs.fetch() should throw on bad API response (${label})`);
}
// fetch() filters out jobs with empty/missing url
const mixedJobs = {
jobs: [
{ title: 'Has URL', url: 'https://solid.jobs/o/1/career-ops', company: 'A', locations: [] },
{ title: 'No URL', url: '', company: 'B', locations: [] },
{ title: 'Missing URL', company: 'C', locations: [] },
],
};
const filtered = await sj.fetch(
{ name: 'SolidJobs IT', careers_url: 'https://solid.jobs/public-api/offers/it?campaign=career-ops' },
{ transport: 'http', fetchJson: async () => mixedJobs, fetchText: async () => '' },
);
if (filtered.length === 1 && filtered[0].title === 'Has URL') pass('solidjobs.fetch() filters out jobs with empty/missing url');
else fail(`solidjobs.fetch() should filter empty URLs, got ${filtered.length} jobs: ${JSON.stringify(filtered)}`);
// fetch() handles string locations (non-array)
const stringLocJobs = { jobs: [{ title: 'Dev', url: 'https://solid.jobs/o/2/career-ops', company: 'X', locations: 'Warsaw' }] };
const strLoc = await sj.fetch(
{ name: 'SolidJobs IT', careers_url: 'https://solid.jobs/public-api/offers/it?campaign=career-ops' },
{ transport: 'http', fetchJson: async () => stringLocJobs, fetchText: async () => '' },
);
if (strLoc[0].location === 'Warsaw') pass('solidjobs.fetch() handles string locations');
else fail(`solidjobs.fetch() string location is ${JSON.stringify(strLoc[0].location)}, expected "Warsaw"`);
// detect() returns null for valid hostname but wrong path
if (sj.detect({ name: 'X', careers_url: 'https://solid.jobs/careers' }) === null) {
pass('solidjobs.detect() rejects solid.jobs URL with wrong path');
} else {
fail('solidjobs.detect() should reject solid.jobs URLs not under /public-api/offers/');
}
// fetch() passes redirect:'error' to fetchJson
let capturedOpts = null;
await sj.fetch(
{ name: 'SolidJobs IT', careers_url: 'https://solid.jobs/public-api/offers/it?campaign=career-ops' },
{ transport: 'http', fetchJson: async (_url, opts) => { capturedOpts = opts; return { jobs: [] }; }, fetchText: async () => '' },
);
if (capturedOpts && capturedOpts.redirect === 'error') pass('solidjobs.fetch() passes redirect:"error" to fetchJson');
else fail(`solidjobs.fetch() should pass redirect:"error", got: ${JSON.stringify(capturedOpts)}`);
// fetch() tolerates malformed array members without crashing
const malformedMembers = { jobs: [null, 7, { title: 'OK', url: 'https://solid.jobs/o/3/career-ops', company: 'Z' }] };
const safeParsed = await sj.fetch(
{ name: 'SolidJobs IT', careers_url: 'https://solid.jobs/public-api/offers/it?campaign=career-ops' },
{ transport: 'http', fetchJson: async () => malformedMembers, fetchText: async () => '' },
);
if (safeParsed.length === 1 && safeParsed[0].url === 'https://solid.jobs/o/3/career-ops') {
pass('solidjobs.fetch() skips malformed jobs members without crashing');
} else {
fail(`solidjobs.fetch() malformed members handling failed: ${JSON.stringify(safeParsed)}`);
}
} catch (e) {
fail(`solidjobs provider tests crashed: ${e.message}`);
}