← back to Homesonspec

collectors/david-weekley/src/index.test.ts

76 lines

import { readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { davidWeekleyAdapter, parseHomes } from "./index";

const FIXTURE = readFileSync(
  join(import.meta.dirname, "..", "fixtures", "dfw-homes-ready-soon.html"),
  "utf8",
);
const PAGE_URL = "https://www.davidweekleyhomes.com/new-homes/tx/dallas-ft-worth/homes-ready-soon";

describe("david-weekley adapter", () => {
  it("has the registry-matching key", () => {
    expect(davidWeekleyAdapter.key).toBe("david-weekley-site");
  });

  it("parses per-home QMI cards with full facts from the DFW list page", () => {
    const homes = parseHomes(FIXTURE);
    expect(homes.length).toBeGreaterThan(0);
    const h = homes[0]!;
    // real per-home fields, not community ranges
    expect(h.jobNumber).toMatch(/^\d{4,}$/);
    expect(h.street).toBeTruthy();
    expect(h.state).toBe("TX");
    expect(typeof h.price).toBe("number");
    expect(h.price! > 100000 && h.price! < 5_000_000).toBe(true);
  });

  it("splits address into street / city / state / zip", () => {
    const homes = parseHomes(FIXTURE);
    const withZip = homes.find((x) => x.zip);
    expect(withZip).toBeTruthy();
    expect(withZip!.zip).toMatch(/^\d{5}$/);
    expect(withZip!.city).toBeTruthy();
    expect(withZip!.street).not.toMatch(/,/); // city/state/zip stripped off
  });

  it("extract() emits inventory_home records that pass basic shape", () => {
    const out = davidWeekleyAdapter.extract({
      url: PAGE_URL,
      retrievedAt: new Date().toISOString(),
      contentType: "text/html",
      body: Buffer.from(FIXTURE, "utf8"),
      contentHash: "test",
    });
    expect(out.errors).toHaveLength(0);
    const homes = out.records.filter((r) => r.entityType === "inventory_home");
    expect(homes.length).toBeGreaterThan(0);
    const f = homes[0]!.fields;
    expect((f.price as { value: number }).value).toBeGreaterThan(0);
    expect((f.street as { value: string }).value).toBeTruthy();
    expect(["MOVE_IN_READY", "UNDER_CONSTRUCTION"]).toContain((f.constructionStatus as { value: string }).value);
    expect((f.builderInventoryId as { value: string }).value).toMatch(/^\d{4,}$/);
    // facts-only: no images
    expect((f.images as { value: string[] }).value).toEqual([]);
  });

  it("does not emit duplicate homes for the same jobNumber", () => {
    const homes = parseHomes(FIXTURE);
    const jobs = homes.map((h) => h.jobNumber);
    expect(new Set(jobs).size).toBe(jobs.length);
  });

  it("emits a community record per distinct community", () => {
    const out = davidWeekleyAdapter.extract({
      url: PAGE_URL,
      retrievedAt: new Date().toISOString(),
      contentType: "text/html",
      body: Buffer.from(FIXTURE, "utf8"),
      contentHash: "test",
    });
    const comms = out.records.filter((r) => r.entityType === "community");
    expect(comms.length).toBeGreaterThan(0);
  });
});