import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import test from "node:test"; import assert from "node:assert/strict"; import { assessProperty } from "../src/assessment.js"; import type { PublicRecordsResolution } from "../src/public-records.js"; const samplePublicRecords: PublicRecordsResolution = { requestedAddress: "4141 Whiteley Dr, Corpus Christi, TX 78418", matchedAddress: "4141 WHITELEY DR, CORPUS CHRISTI, TX, 78418", latitude: 27.6138, longitude: -97.3024, geoid: "483550031013005", state: { name: "Texas", code: "TX", fips: "48" }, county: { name: "Nueces County", fips: "355", geoid: "48355" }, officialLinks: { censusGeocoder: "https://geocoding.geo.census.gov/example", texasCountyDirectory: "https://comptroller.texas.gov/taxes/property-tax/county-directory/nueces.php", texasPropertyTaxPortal: "https://texas.gov/PropertyTaxes" }, appraisalDistrict: { "Chief Appraiser": "Debra Morin, Interim", Website: "http://www.ncadistrict.com/", directoryPage: "https://comptroller.texas.gov/taxes/property-tax/county-directory/nueces.php" }, taxAssessorCollector: { "Tax Assessor-Collector": "Kevin Kieschnick", Website: "http://www.nuecesco.com" }, lookupRecommendations: [ "Start from the official public-record jurisdiction instead of a listing-site geo ID." ], sourceIdentifierHints: { parcelId: "14069438" }, propertyDetails: { source: "nueces-esearch", sourceUrl: "https://esearch.nuecescad.net/property/view/14069438?year=2026", propertyId: "14069438", ownerName: "Fiorini Family Trust", situsAddress: "4141 WHITELEY DR, CORPUS CHRISTI, TX, 78418", legalDescription: "LOT 4 BLOCK 3 EXAMPLE SUBDIVISION", landValue: 42000, improvementValue: 99000, assessedTotalValue: 141000, exemptions: ["Homestead"], notes: [ "Official CAD property detail page exposed owner, value, and exemption data." ] } }; test("assessProperty asks for assessment purpose before building a decision-grade assessment", async () => { const result = await assessProperty( { address: "4141 Whiteley Dr, Corpus Christi, TX 78418" } ); assert.equal(result.ok, true); assert.equal(result.needsAssessmentPurpose, true); assert.equal(result.needsRecipientEmails, false); assert.equal(result.outputPath, null); assert.match(result.message, /assessment purpose/i); assert.equal(result.reportPayload, null); }); test("assessProperty auto-discovers listing sources, runs Zillow photos first, and does not ask for email during analysis-only runs", async () => { const result = await assessProperty( { address: "4141 Whiteley Dr, Corpus Christi, TX 78418", assessmentPurpose: "investment property", listingGeoId: "233290", parcelId: "14069438" }, { resolvePublicRecordsFn: async () => samplePublicRecords, discoverListingSourcesFn: async () => ({ attempts: [ "Zillow discovery located a property page from the address.", "HAR discovery located a property page from the address." ], zillowUrl: "https://www.zillow.com/homedetails/4141-Whiteley-Dr-Corpus-Christi-TX-78418/2103723704_zpid/", harUrl: "https://www.har.com/homedetail/4141-whiteley-dr-corpus-christi-tx-78418/14069438" }), extractPhotoDataFn: async (source, url) => ({ source, requestedUrl: url, finalUrl: url, expectedPhotoCount: 29, complete: true, photoCount: 29, imageUrls: ["https://photos.example/1.jpg", "https://photos.example/2.jpg"], notes: [`${source} extractor succeeded.`] }) } ); assert.equal(result.ok, true); assert.equal(result.needsAssessmentPurpose, false); assert.equal(result.needsRecipientEmails, false); assert.equal(result.outputPath, null); assert.doesNotMatch(result.message, /target email/i); assert.match(result.message, /ready to render|recipient email is only needed when you want the pdf/i); assert.equal(result.reportPayload?.subjectProperty?.address, samplePublicRecords.matchedAddress); assert.equal(result.reportPayload?.publicRecords?.jurisdiction, "Nueces County Appraisal District"); assert.equal(result.reportPayload?.publicRecords?.accountNumber, "14069438"); assert.equal(result.reportPayload?.publicRecords?.ownerName, "Fiorini Family Trust"); assert.equal(result.reportPayload?.publicRecords?.landValue, 42000); assert.equal(result.reportPayload?.publicRecords?.improvementValue, 99000); assert.equal(result.reportPayload?.publicRecords?.assessedTotalValue, 141000); assert.deepEqual(result.reportPayload?.publicRecords?.exemptions, ["Homestead"]); assert.match( String(result.reportPayload?.snapshot?.join(" ")), /141,000|141000|assessed/i ); assert.match( String(result.reportPayload?.risksAndDiligence?.join(" ")), /official cad property detail page exposed owner, value, and exemption data/i ); assert.equal(result.reportPayload?.photoReview?.status, "completed"); assert.equal(result.reportPayload?.photoReview?.source, "zillow"); assert.equal(result.reportPayload?.photoReview?.photoCount, 29); assert.match( String(result.reportPayload?.verdict?.offerGuidance), /investment property/i ); assert.match( String(result.reportPayload?.carryView?.[0]), /income property/i ); assert.deepEqual(result.reportPayload?.recipientEmails, []); }); test("assessProperty uses parcel/APN hints extracted from Zillow before CAD lookup when parcel ID was not provided", async () => { const seenPublicRecordOptions: Array> = []; const result = await assessProperty( { address: "6702 Everhart Rd APT T106, Corpus Christi, TX 78413", assessmentPurpose: "college housing for daughter attending TAMU-CC" }, { resolvePublicRecordsFn: async (_address, options) => { seenPublicRecordOptions.push({ ...options }); return samplePublicRecords; }, discoverListingSourcesFn: async () => ({ attempts: ["Zillow discovery located a property page from the address."], zillowUrl: "https://www.zillow.com/homedetails/6702-Everhart-Rd-APT-T106-Corpus-Christi-TX-78413/2067445642_zpid/", harUrl: null }), extractZillowIdentifierHintsFn: async () => ({ parcelId: "1234567890", notes: ["Zillow listing exposed parcel/APN number 1234567890."] }), extractPhotoDataFn: async (source, url) => ({ source, requestedUrl: url, finalUrl: url, expectedPhotoCount: 29, complete: true, photoCount: 29, imageUrls: ["https://photos.example/1.jpg"], notes: [`${source} extractor succeeded.`] }) } ); assert.equal(result.ok, true); assert.equal(seenPublicRecordOptions.length, 1); assert.equal(seenPublicRecordOptions[0]?.parcelId, "1234567890"); }); test("assessProperty asks for recipient email only when PDF render is explicitly requested", async () => { const result = await assessProperty( { address: "4141 Whiteley Dr, Corpus Christi, TX 78418", assessmentPurpose: "investment property", output: path.join(os.tmpdir(), `property-assess-missing-email-${Date.now()}.pdf`) }, { resolvePublicRecordsFn: async () => samplePublicRecords, discoverListingSourcesFn: async () => ({ attempts: ["Zillow discovery located a property page from the address."], zillowUrl: "https://www.zillow.com/homedetails/4141-Whiteley-Dr-Corpus-Christi-TX-78418/2103723704_zpid/", harUrl: null }), extractPhotoDataFn: async (source, url) => ({ source, requestedUrl: url, finalUrl: url, expectedPhotoCount: 29, complete: true, photoCount: 29, imageUrls: ["https://photos.example/1.jpg"], notes: [`${source} extractor succeeded.`] }) } ); assert.equal(result.ok, true); assert.equal(result.needsRecipientEmails, true); assert.equal(result.outputPath, null); assert.match(result.message, /target email/i); }); test("assessProperty falls back to HAR when Zillow photo extraction fails", async () => { const result = await assessProperty( { address: "4141 Whiteley Dr, Corpus Christi, TX 78418", assessmentPurpose: "vacation home" }, { resolvePublicRecordsFn: async () => samplePublicRecords, discoverListingSourcesFn: async () => ({ attempts: ["Address-based discovery found Zillow and HAR candidates."], zillowUrl: "https://www.zillow.com/homedetails/4141-Whiteley-Dr-Corpus-Christi-TX-78418/2103723704_zpid/", harUrl: "https://www.har.com/homedetail/4141-whiteley-dr-corpus-christi-tx-78418/14069438" }), extractPhotoDataFn: async (source, url) => { if (source === "zillow") { throw new Error(`zillow failed for ${url}`); } return { source, requestedUrl: url, finalUrl: url, expectedPhotoCount: 29, complete: true, photoCount: 29, imageUrls: ["https://photos.har.example/1.jpg"], notes: ["HAR extractor succeeded after Zillow failed."] }; } } ); assert.equal(result.ok, true); assert.equal(result.reportPayload?.photoReview?.status, "completed"); assert.equal(result.reportPayload?.photoReview?.source, "har"); assert.match( String(result.reportPayload?.photoReview?.attempts?.join(" ")), /zillow/i ); assert.match( String(result.reportPayload?.verdict?.offerGuidance), /vacation home/i ); }); test("assessProperty does not render a PDF from a preliminary helper payload even when recipient email is present", async () => { const outputPath = path.join(os.tmpdir(), `property-assess-command-${Date.now()}.pdf`); let renderCalls = 0; const result = await assessProperty( { address: "4141 Whiteley Dr, Corpus Christi, TX 78418", assessmentPurpose: "rental for my daughter in college", recipientEmails: ["buyer@example.com"], output: outputPath }, { resolvePublicRecordsFn: async () => samplePublicRecords, discoverListingSourcesFn: async () => ({ attempts: ["No listing sources discovered from the address."], zillowUrl: null, harUrl: null }), renderReportPdfFn: async () => { renderCalls += 1; return outputPath; } } ); assert.equal(result.ok, true); assert.equal(result.needsAssessmentPurpose, false); assert.equal(result.needsRecipientEmails, false); assert.equal(renderCalls, 0); assert.equal(result.pdfReady, false); assert.equal(result.outputPath, null); assert.match(result.message, /preliminary|decision-grade|cannot render/i); }); test("assessProperty prioritizes student housing guidance over investment fallback keywords", async () => { const result = await assessProperty( { address: "1011 Ennis Joslin Rd APT 235, Corpus Christi, TX 78412", assessmentPurpose: "college housing for daughter attending TAMU-CC; prioritize proximity, safety/livability, and resale/rental fallback" }, { resolvePublicRecordsFn: async () => samplePublicRecords, discoverListingSourcesFn: async () => ({ attempts: ["Zillow discovery located a property page from the address."], zillowUrl: "https://www.zillow.com/homedetails/1011-Ennis-Joslin-Rd-APT-235-Corpus-Christi-TX-78412/28848927_zpid/", harUrl: null }), extractPhotoDataFn: async (source, url) => ({ source, requestedUrl: url, finalUrl: url, expectedPhotoCount: 20, complete: true, photoCount: 20, imageUrls: ["https://photos.example/1.jpg"], notes: [`${source} extractor succeeded.`] }) } ); assert.match( String(result.reportPayload?.verdict?.offerGuidance), /daughter|student|practicality|safety/i ); assert.doesNotMatch( String(result.reportPayload?.verdict?.offerGuidance), /income property|investment property/i ); assert.match( String(result.reportPayload?.carryView?.[0]), /parent-risk|upkeep burden|renting/i ); });