253 lines
7.8 KiB
Python
253 lines
7.8 KiB
Python
from job_research.apec.normalize import normalize_apec_listing
|
|
|
|
|
|
def test_normalize_apec_listing_extracts_minimal_shape() -> None:
|
|
html = """
|
|
<html>
|
|
<body>
|
|
<main class="container-details-offer">
|
|
<h1>Data Engineer F/H</h1>
|
|
<div class="card-offer">
|
|
<div class="ref-offre">Ref. Apec : 178554452W</div>
|
|
<ul class="details-offer-list mb-20">
|
|
<li>CLOUD TEMPLE</li>
|
|
<li>1 <span> CDI </span></li>
|
|
<li>Puteaux - 92</li>
|
|
</ul>
|
|
<p>Publiée le 20/04/2026 Actualisée le 02/06/2026</p>
|
|
</div>
|
|
<article class="card card-ents mb-20">
|
|
<div class="list-hzt mb-20">
|
|
<span class="ents-name">CLOUD TEMPLE</span>
|
|
</div>
|
|
</article>
|
|
<div class="details-post">
|
|
<h4>Salaire</h4>
|
|
<span>A partir de 70 k€ brut annuel</span>
|
|
</div>
|
|
<div class="details-post">
|
|
<h4>Prise de poste</h4>
|
|
<span>Dès que possible</span>
|
|
</div>
|
|
<div class="details-post">
|
|
<h4>Expérience</h4>
|
|
<span>Minimum 7 ans</span>
|
|
</div>
|
|
<div class="details-post">
|
|
<h4>Descriptif du poste</h4>
|
|
<p>Build pipelines</p>
|
|
<div class="nested-late-sections">
|
|
<h4>Profil recherché</h4>
|
|
<p>Python / SQL</p>
|
|
<h4>Compétences attendues</h4>
|
|
<p>Ignored</p>
|
|
<h4>Entreprise</h4>
|
|
<p>Ignored</p>
|
|
<div class="recruiter">Ignored recruiter info</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</body>
|
|
</html>
|
|
"""
|
|
|
|
listing = normalize_apec_listing(
|
|
url="https://example.test/job/123",
|
|
html=html,
|
|
fetched_at="2026-06-01T10:00:00Z",
|
|
source_job_id="job-123",
|
|
)
|
|
|
|
assert listing.source == "apec"
|
|
assert listing.source_job_id == "job-123"
|
|
assert listing.url == "https://example.test/job/123"
|
|
assert listing.title == "Data Engineer F/H"
|
|
assert listing.company == "CLOUD TEMPLE"
|
|
assert listing.location == "Puteaux - 92"
|
|
assert listing.contract_type == "CDI"
|
|
assert listing.description_text == "Build pipelines"
|
|
assert listing.published_at == "2026-04-20"
|
|
assert listing.refreshed_at == "2026-06-02"
|
|
assert listing.fetched_at == "2026-06-01T10:00:00Z"
|
|
|
|
|
|
def test_normalize_apec_listing_uses_details_offer_list_company_fallback() -> None:
|
|
html = """
|
|
<html>
|
|
<body>
|
|
<main class="container-details-offer">
|
|
<h1>Data Engineer F/H</h1>
|
|
<div class="card-offer">
|
|
<div class="ref-offre">Ref. Apec : 178554452W</div>
|
|
<ul class="details-offer-list mb-20">
|
|
<li>Fallback Company</li>
|
|
<li>1 <span> CDI </span></li>
|
|
<li>Puteaux - 92</li>
|
|
</ul>
|
|
<p>Publiée le 20/04/2026 Actualisée le 02/06/2026</p>
|
|
</div>
|
|
<div class="details-post">
|
|
<h4>Salaire</h4>
|
|
<span>A partir de 70 k€ brut annuel</span>
|
|
</div>
|
|
<div class="details-post">
|
|
<h4>Prise de poste</h4>
|
|
<span>Dès que possible</span>
|
|
</div>
|
|
<div class="details-post">
|
|
<h4>Expérience</h4>
|
|
<span>Minimum 7 ans</span>
|
|
</div>
|
|
<div class="details-post">
|
|
<h4>Descriptif du poste</h4>
|
|
<p>Build pipelines</p>
|
|
<div class="nested-late-sections">
|
|
<h4>Profil recherché</h4>
|
|
<p>Python / SQL</p>
|
|
<h4>Compétences attendues</h4>
|
|
<p>Ignored</p>
|
|
<h4>Entreprise</h4>
|
|
<p>Ignored</p>
|
|
<div class="recruiter">Ignored recruiter info</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</body>
|
|
</html>
|
|
"""
|
|
|
|
listing = normalize_apec_listing(
|
|
url="https://example.test/job/123",
|
|
html=html,
|
|
fetched_at="2026-06-01T10:00:00Z",
|
|
source_job_id=None,
|
|
)
|
|
|
|
assert listing.company == "Fallback Company"
|
|
assert listing.description_text == "Build pipelines"
|
|
assert listing.refreshed_at == "2026-06-02"
|
|
|
|
|
|
def test_normalize_apec_listing_records_warnings_for_fallback_and_missing_fields() -> None:
|
|
html = """
|
|
<html>
|
|
<body>
|
|
<main class="container-details-offer">
|
|
<div class="card-offer">
|
|
<div class="ref-offre">Ref. Apec : 178554452W</div>
|
|
<ul class="details-offer-list mb-20">
|
|
<li>Fallback Company</li>
|
|
<li>1 CDI</li>
|
|
</ul>
|
|
</div>
|
|
<article class="card card-ents mb-20">
|
|
<div class="list-hzt mb-20">
|
|
<span class="card-ents-quote">Fallback Company</span>
|
|
</div>
|
|
</article>
|
|
</main>
|
|
<h1>Fallback Title</h1>
|
|
</body>
|
|
</html>
|
|
"""
|
|
|
|
listing = normalize_apec_listing(
|
|
url="https://example.test/job/123",
|
|
html=html,
|
|
fetched_at="2026-06-01T10:00:00Z",
|
|
source_job_id=None,
|
|
)
|
|
|
|
assert [warning.field for warning in listing.warnings] == [
|
|
"title",
|
|
"location",
|
|
"contract_type",
|
|
"description_text",
|
|
"source_job_id",
|
|
"company",
|
|
"published_at",
|
|
]
|
|
|
|
|
|
def test_normalize_apec_listing_records_warnings_for_placeholder_text_values() -> None:
|
|
html = """
|
|
<html>
|
|
<body>
|
|
<main class="container-details-offer">
|
|
<h1> N/A </h1>
|
|
<div class="card-offer">
|
|
<div class="ref-offre">Ref. Apec : 178554452W</div>
|
|
<ul class="details-offer-list mb-20">
|
|
<li>Example Corp</li>
|
|
<li>1 <span> N/A </span></li>
|
|
<li> - </li>
|
|
</ul>
|
|
<p>Publiée le 20/04/2026 Actualisée le 02/06/2026</p>
|
|
</div>
|
|
<article class="card card-ents mb-20">
|
|
<div class="list-hzt mb-20">
|
|
<span class="ents-name">Example Corp</span>
|
|
</div>
|
|
</article>
|
|
<div class="details-post">
|
|
<h4>Descriptif du poste</h4>
|
|
<p>Build pipelines</p>
|
|
</div>
|
|
</main>
|
|
</body>
|
|
</html>
|
|
"""
|
|
|
|
listing = normalize_apec_listing(
|
|
url="https://example.test/job/123",
|
|
html=html,
|
|
fetched_at="2026-06-01T10:00:00Z",
|
|
source_job_id="178554452W",
|
|
)
|
|
|
|
assert listing.title is None
|
|
assert listing.location is None
|
|
assert listing.contract_type is None
|
|
assert [warning.field for warning in listing.warnings] == ["title", "location", "contract_type"]
|
|
|
|
|
|
def test_normalize_apec_listing_records_warning_for_placeholder_company() -> None:
|
|
html = """
|
|
<html>
|
|
<body>
|
|
<main class="container-details-offer">
|
|
<h1>Data Engineer F/H</h1>
|
|
<div class="card-offer">
|
|
<div class="ref-offre">Ref. Apec : 178554452W</div>
|
|
<ul class="details-offer-list mb-20">
|
|
<li>Example Corp</li>
|
|
<li>1 <span> CDI </span></li>
|
|
<li>Puteaux - 92</li>
|
|
</ul>
|
|
<p>Publiée le 20/04/2026 Actualisée le 02/06/2026</p>
|
|
</div>
|
|
<article class="card card-ents mb-20">
|
|
<div class="list-hzt mb-20">
|
|
<span class="ents-name">N/A</span>
|
|
</div>
|
|
</article>
|
|
<div class="details-post">
|
|
<h4>Descriptif du poste</h4>
|
|
<p>Build pipelines</p>
|
|
</div>
|
|
</main>
|
|
</body>
|
|
</html>
|
|
"""
|
|
|
|
listing = normalize_apec_listing(
|
|
url="https://example.test/job/123",
|
|
html=html,
|
|
fetched_at="2026-06-01T10:00:00Z",
|
|
source_job_id="178554452W",
|
|
)
|
|
|
|
assert listing.company is None
|
|
assert listing.refreshed_at == "2026-06-02"
|
|
assert [warning.field for warning in listing.warnings] == ["company"]
|