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" } }; 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 asks for recipient email", 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, true); assert.equal(result.outputPath, null); assert.match(result.message, /target email/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?.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 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 renders a PDF when recipient email is present", async () => { const outputPath = path.join(os.tmpdir(), `property-assess-command-${Date.now()}.pdf`); 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 }) } ); assert.equal(result.ok, true); assert.equal(result.needsAssessmentPurpose, false); assert.equal(result.needsRecipientEmails, false); assert.equal(result.outputPath, outputPath); const stat = await fs.promises.stat(outputPath); assert.ok(stat.size > 1000); });