← DASHBOARDUnitIntegrationE2EConsistency

Pre-scrape: Unit Tests — SOF MEDICA S.A.

Started: 2026-10-25 19:38:03
Suites (12)
12 passed
0 failed
0 pending
Tests (172)
172 passed
0 failed
0 pending
firstMatch — cascade primitive
returns the primary strategy when it yields a value
passed
0.006s
firstMatch — cascade primitive
falls through to the backup when the primary is empty
passed
0.002s
firstMatch — cascade primitive
falls through when the primary THROWS (per-strategy try/catch)
passed
0.001s
firstMatch — cascade primitive
uses the regex last-resort when every DOM strategy fails
passed
0.001s
firstMatch — cascade primitive
returns {value:null} and WARNS once when all strategies fail
passed
0.002s
firstMatch — cascade primitive
stays silent on total failure when opts.silent is set
passed
0s
asList
wraps a single selector, passes an array through, drops falsy
passed
0s
cssText / structuralText builders
cssText reads the first match under the scope
passed
0.001s
cssText / structuralText builders
structuralText reads itemprop/meta content hooks
passed
0.001s
textFromHtml
strips tags and collapses whitespace
passed
0.002s
textFromHtml
returns null for empty input
passed
0.001s
jsonLdJobPostings
extracts JobPosting objects from a bare object, an array and an @graph
passed
0.002s
jsonLdJobPostings
ignores malformed JSON-LD blocks instead of throwing
passed
0.001s
scope.href — the URL cascade (real <a href>, not a guessed permalink)
finds the only anchor with no selector given
passed
0.002s
scope.href — the URL cascade (real <a href>, not a guessed permalink)
prefers an explicit selector when given
passed
0.002s
scope.href — the URL cascade (real <a href>, not a guessed permalink)
falls back to the first anchor when the selector misses
passed
0.002s
scope.href — the URL cascade (real <a href>, not a guessed permalink)
ignores fragment and javascript: links
passed
0.002s
scope.href — the URL cascade (real <a href>, not a guessed permalink)
returns null when the block has no anchor
passed
0.002s
locateArticles — article-level cascade
mode css:<selector> when a primary selector matches
passed
0.002s
locateArticles — article-level cascade
uses a fallback selector when the primary misses
passed
0.002s
locateArticles — article-level cascade
mode jsonld when there is no article markup but JobPosting JSON-LD exists
passed
0.001s
locateArticles — article-level cascade
mode regex:<article> when selectors miss and there is no JSON-LD
passed
0.003s
locateArticles — article-level cascade
mode none when nothing matches at all
passed
0.001s
locateArticles — article-level cascade
skips an invalid selector without crashing
passed
0.001s
scraper/api.js > querySOLR
should return response object with docs
passed
0.01s
scraper/api.js > querySOLR
should return empty docs when no jobs found
passed
0.002s
scraper/api.js > querySOLR
should throw on HTTP error
passed
0.074s
scraper/api.js > querySOLR
should retry a transient 503 and then succeed
passed
0.016s
scraper/api.js > querySOLR
should not retry a 4xx response
passed
0.001s
scraper/api.js > upsertJobs
should accept array of jobs
passed
0.007s
scraper/api.js > upsertJobs
should throw on HTTP error
passed
0.001s
scraper/api.js > upsertJobs
should retry a transient 502 and then succeed
passed
0.004s
scraper/api.js > deleteJobByUrl
should delete a job by URL
passed
0.001s
scraper/api.js > deleteJobByUrl
should throw on HTTP error
passed
0.001s
scraper/api.js > deleteJobsByCIF
should delete all jobs for a CIF
passed
0.001s
scraper/api.js > deleteJobsByCIF
should throw on HTTP error
passed
0s
scraper/api.js > CIF zero-padding (regression)
getCompanyByCif pads the CIF in the query string
passed
0s
scraper/api.js > CIF zero-padding (regression)
querySOLR pads the CIF in the query string
passed
0.001s
scraper/api.js > CIF zero-padding (regression)
upsertCompany pads the id field in the request body
passed
0.001s
scraper/api.js > CIF zero-padding (regression)
deleteJobsByCIF pads the cif field in the request body
passed
0.001s
scraper/api.js > CIF zero-padding (regression)
upsertJobs pads every job's cif field in the request body
passed
0.001s
scraper/api.js > CIF zero-padding (regression)
already-padded CIFs pass through unchanged (idempotent)
passed
0.001s
scraper/api.js > Data Integrity
should not have duplicate URLs for same CIF
passed
0s
scraper/api.js > Data Integrity
should have valid CIF format for all jobs
passed
0.001s
scraper/api.js > Data Integrity
should detect invalid CIF format
passed
0s
scraper/api.js > Data Integrity
should have valid status values
passed
0.001s
scraper/anaf.js > searchCompany
should return array of companies for valid brand
passed
0.003s
scraper/anaf.js > searchCompany
should return empty array for non-existent brand
passed
0.001s
scraper/anaf.js > searchCompany
should include statusLabel in results
passed
0.001s
scraper/anaf.js > searchCompany
should fallback to CUIFirma when ANAF search fails
passed
0.046s
scraper/anaf.js > searchCompany
should encode brand name in URL
passed
0.001s
scraper/anaf.js > getCompanyFromANAF
should return company data for valid CIF
passed
0.004s
scraper/anaf.js > getCompanyFromANAF
should fallback to CUIScan when ANAF fails
passed
0.003s
scraper/anaf.js > getCompanyFromANAF
should throw when both ANAF and CUIScan fail
passed
0.017s
scraper/anaf.js > getCompanyFromANAF
should handle API-level error response
passed
0.003s
scraper/anaf.js > getCompanyFromANAF
should return null when data is null
passed
0.006s
scraper/anaf.js > getCompanyFromANAFWithFallback
should return fresh data when API works
passed
0.001s
scraper/anaf.js > getCompanyFromANAFWithFallback
should use cached data when API fails
passed
0.008s
scraper/anaf.js > getCompanyFromANAFWithFallback
should throw when API fails and no cache available
passed
0.003s
company.js > getCompanyData (no cache)
should fetch the company via direct CIF lookup and return company data
passed
0.02s
company.js > getCompanyData (no cache)
should throw when ANAF returns no data
passed
0.024s
company.js > getCompanyData (no cache)
should throw when ANAF returns no company name
passed
0.004s
company.js > getCompanyData (with cache)
should use cached company data when available
passed
0.008s
company.js > validateAndGetCompany
should return company data with status active
passed
0.024s
company.js > validateAndGetCompany
should return inactive status when company is inactive
passed
0.013s
company.js > validateAndGetCompany
deletes jobs by CIF when an inactive company still has jobs in SOLR
passed
0.016s
company.js > validateAndGetCompany
regression: dry_run=true must never call deleteJobsByCIF, even with jobs present
passed
0.02s
index.js Component Tests > slugify
strips Romanian diacritics and lowercases
passed
0.006s
index.js Component Tests > slugify
collapses separators and trims dashes
passed
0.001s
index.js Component Tests > parseDeadline
converts a DD.MM.YYYY deadline to an end-of-day ISO string
passed
0.001s
index.js Component Tests > parseDeadline
returns undefined when no date is present
passed
0.001s
index.js Component Tests > matchSitemapUrl
matches exact slugs
passed
0.001s
index.js Component Tests > matchSitemapUrl
tolerates a trailing -2 disambiguation suffix
passed
0.001s
index.js Component Tests > matchSitemapUrl
tolerates a small typo in the sitemap slug (edit distance <= 2)
passed
0.003s
index.js Component Tests > matchSitemapUrl
returns null when nothing is close enough
passed
0.001s
index.js Component Tests > parseListing
extracts one item per article with a decoded, trimmed title
passed
0.072s
index.js Component Tests > parseListing
carries the deadline when present, undefined otherwise
passed
0.006s
index.js Component Tests > parseListing
carries the real scraped url, not a guessed slug
passed
0.006s
index.js Component Tests > parseListing
returns an empty array when the selector matches nothing
passed
0.004s
index.js Component Tests > parseListing
keeps two postings that share a title but have different URLs (dedup is title+URL, not title alone)
passed
0.021s
index.js Component Tests > parseListing
still drops a true duplicate match (same title AND same URL) from an overly broad fallback selector
passed
0.005s
index.js Component Tests > parseListing
skips an unconfigured {{PLACEHOLDER}} primary selector and uses a fallback
passed
0.023s
index.js Component Tests > parseListing > self-healing when the primary markup breaks
recovers via a fallback article selector when the class is renamed
passed
0.006s
index.js Component Tests > parseListing > self-healing when the primary markup breaks
recovers the title via a fallback heading selector when .job__title is gone
passed
0.002s
index.js Component Tests > parseListing > self-healing when the primary markup breaks
recovers the title via the anchor text when all headings are gone
passed
0.002s
index.js Component Tests > parseListing > self-healing when the primary markup breaks
falls back to JSON-LD JobPosting when there is no article markup at all
passed
0.003s
index.js Component Tests > parseListing > self-healing when the primary markup breaks
falls back to regex <article> slicing when the container selectors all miss
passed
0.005s
index.js Component Tests > parseListing > self-healing when the primary markup breaks
returns [] and does not throw when the page is unrecognisable (canary feeds off this)
passed
0.001s
index.js Component Tests > transformJobsForSOLR
should filter locations to only Romanian cities
passed
0.001s
index.js Component Tests > transformJobsForSOLR
should keep company uppercase
passed
0s
index.js Component Tests > transformJobsForSOLR
should normalize workmode values
passed
0.001s
index.js Component Tests > transformJobsForSOLR
should preserve expirationdate through the transform
passed
0s
index.js Component Tests > transformJobsForSOLR
should handle empty jobs array
passed
0.001s
index.js Component Tests > mapToJobModel
should map a raw job to the job model format
passed
0.001s
index.js Component Tests > mapToJobModel
should remove undefined fields
passed
0.001s
generateJobsMarkdown > company section
includes company name as h1
passed
0.004s
generateJobsMarkdown > company section
includes CIF
passed
0s
generateJobsMarkdown > company section
includes brand
passed
0s
generateJobsMarkdown > company section
includes status
passed
0.001s
generateJobsMarkdown > company section
includes website as markdown link
passed
0.001s
generateJobsMarkdown > company section
includes career page as markdown link
passed
0s
generateJobsMarkdown > company section
includes lastScraped date
passed
0.001s
generateJobsMarkdown > company section
omits optional fields when not present
passed
0.001s
generateJobsMarkdown > jobs section
shows job count in heading
passed
0s
generateJobsMarkdown > jobs section
shows 0 when no jobs
passed
0s
generateJobsMarkdown > jobs section
includes job title as h3
passed
0s
generateJobsMarkdown > jobs section
includes job URL as markdown link
passed
0.001s
generateJobsMarkdown > jobs section
includes workmode
passed
0s
generateJobsMarkdown > jobs section
includes location
passed
0s
generateJobsMarkdown > jobs section
includes tags
passed
0s
generateJobsMarkdown > jobs section
includes status
passed
0s
generateJobsMarkdown > jobs section
renders multiple jobs
passed
0.001s
generateJobsMarkdown > jobs section
handles job with no optional fields
passed
0s
generateJobsMarkdown > output format
returns a non-empty string
passed
0.001s
generateJobsMarkdown > output format
includes a generated timestamp
passed
0s
generateJobsMarkdown > markdown escaping
escapes # in job titles
passed
0.001s
generateJobsMarkdown > markdown escaping
escapes * in job titles
passed
0s
generateJobsMarkdown > markdown escaping
escapes [ ] in company name
passed
0.001s
generateJobsMarkdown > markdown escaping
escapes ` in tags
passed
0s
generateJobsMarkdown > markdown escaping
escapes # in location
passed
0.001s
renderHtml
returns the DOM, waits for the selector and closes the browser
passed
0.005s
renderHtml
closes the browser even when navigation fails
passed
0.016s
renderHtml
reports a missing playwright package as BrowserUnavailable
passed
0.001s
renderHtml
reports missing browser binaries as BrowserUnavailable
passed
0.003s
getHtml
static mode never launches a browser
passed
0.001s
getHtml
browser mode skips the static fetch
passed
0.001s
getHtml
auto keeps the static HTML when it has jobs
passed
0s
getHtml
auto renders when the static HTML has no jobs
passed
0.003s
getHtml
auto falls back to the static HTML when no browser is available
passed
0.001s
getHtml
auto does not swallow real rendering errors
passed
0.008s
getHtml
rejects an unknown mode
passed
0.003s
getHtml
ships defaulting to static
passed
0s
scraper/job-validator.js > validateByHead
returns active when HEAD response is ok
passed
0.003s
scraper/job-validator.js > validateByHead
returns expired on non-2xx response
passed
0.001s
scraper/job-validator.js > validateByHead
returns error when fetch throws
passed
0.001s
scraper/job-validator.js > validateByHead
issues a HEAD request
passed
0.002s
scraper/job-validator.js > validateByContent
returns active when body has no expired keywords
passed
0.001s
scraper/job-validator.js > validateByContent
returns expired when body has an expired keyword
passed
0s
scraper/job-validator.js > validateByContent
returns expired on a hard 404 even without a keyword match
passed
0.001s
scraper/job-validator.js > validateByContent
accepts custom keywords
passed
0.001s
scraper/job-validator.js > validateByContent
returns error when fetch throws
passed
0s
scraper/job-validator.js > DEFAULT_EXPIRED_KEYWORDS
is a non-empty array of lowercase strings
passed
0.001s
validateJob
accepts a well-formed job
passed
0.004s
validateJob > url
rejects an empty url
passed
0.001s
validateJob > url
rejects a non-URL string
passed
0.001s
validateJob > url
rejects a non-http(s) protocol
passed
0s
validateJob > title
rejects an empty / whitespace title
passed
0s
validateJob > title
rejects a title containing HTML
passed
0.001s
validateJob > title
rejects a title over 200 chars
passed
0s
validateJob > location
rejects a non-array location
passed
0.001s
validateJob > location
rejects an empty entry
passed
0s
validateJob > salary
accepts a normal salary string
passed
0.001s
validateJob > salary
rejects a negative amount
passed
0.001s
validateJob > salary
rejects a non-string salary
passed
0s
validateJob
reports multiple errors at once
passed
0.001s
validateJob
rejects a non-object
passed
0s
filterValidJobs
keeps the good, drops the bad, and logs each drop
passed
0.002s
filterValidJobs
returns everything when all jobs are valid and logs nothing
passed
0.001s
assertScrapeYieldedJobs — canary
throws on an empty array (aborts before any write)
passed
0.014s
assertScrapeYieldedJobs — canary
throws on a zero count
passed
0.002s
assertScrapeYieldedJobs — canary
returns the count when jobs are present
passed
0s
parseWorkable
keeps only Romanian jobs, once each
passed
0.002s
parseWorkable
maps city, remote workmode and trims the title
passed
0.001s
parseWorkable
survives an empty or malformed payload
passed
0.001s
parseSmartRecruiters
builds permalinks and filters by country
passed
0s
parseSmartRecruiters
drops non-city locations and marks remote
passed
0.001s
parseTeamtailor
parses items, decodes entities and dedupes by link
passed
0.001s
parseTeamtailor
returns [] for an empty feed
passed
0s
parseJsonResponse
returns the parsed JSON body
passed
0.003s
parseJsonResponse
turns an HTML error page into a clear error
passed
0.007s
dropDeadUrls
keeps active jobs and drops expired or erroring ones
passed
0.023s
dropDeadUrls
returns an empty array when every job fails live validation
passed
0.012s