diff --git a/biome.json b/biome.json index f97f513..1435f87 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.2.4/schema.json", + "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", "vcs": { "enabled": true, "clientKind": "git" diff --git a/package.json b/package.json index 7140580..75570cc 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "scripts": { "clean": "rm -rf dist", "build": "npm run clean && tsc -p tsconfig.build.json", - "test": "tsc && node --test dist/**/*.test.js", + "test": "npm run clean && tsc -p tsconfig.json && node --test dist/**/*.test.js", "lint": "biome check --write", "prepublishOnly": "npm run build" }, diff --git a/src/api/__tests__/lookup.smoke.test.ts b/src/api/__tests__/lookup.smoke.test.ts index dded28b..9d22ec9 100644 --- a/src/api/__tests__/lookup.smoke.test.ts +++ b/src/api/__tests__/lookup.smoke.test.ts @@ -1,3 +1,5 @@ +/** biome-ignore-all lint/style/noNonNullAssertion: this is fine for tests */ + import assert from "node:assert/strict"; import test from "node:test"; import { lookupDomain } from "../lookup.js"; @@ -5,6 +7,7 @@ import { lookupDomain } from "../lookup.js"; // Run only when SMOKE=1 to avoid flakiness and network in CI by default const shouldRun = process.env.SMOKE === "1"; +// Basic sanity: either RDAP or WHOIS should succeed for example.com (shouldRun ? test : test.skip)( "lookupDomain smoke test (example.com)", async () => { @@ -18,3 +21,106 @@ const shouldRun = process.env.SMOKE === "1"; assert.ok(res.record?.source === "rdap" || res.record?.source === "whois"); }, ); + +// RDAP-only smoke for reserved example domains (.com/.net/.org) +const rdapCases: Array<{ domain: string; tld: string; expectDs?: boolean }> = [ + { domain: "example.com", tld: "com", expectDs: true }, + { domain: "example.net", tld: "net", expectDs: true }, + { domain: "example.org", tld: "org" }, +]; + +for (const c of rdapCases) { + (shouldRun ? test : test.skip)( + `RDAP-only lookup for ${c.domain}`, + async () => { + const res = await lookupDomain(c.domain, { + timeoutMs: 15000, + rdapOnly: true, + }); + assert.equal(res.ok, true, res.error); + const rec = res.record!; + assert.equal(rec.tld, c.tld); + assert.equal(rec.source, "rdap"); + // Registrar ID is IANA (376) for example domains + assert.equal(rec.registrar?.ianaId, "376"); + if (c.tld !== "org") { + // .com/.net often include the IANA reserved name explicitly + assert.ok( + (rec.registrar?.name || "") + .toLowerCase() + .includes("internet assigned numbers authority"), + ); + } + // IANA nameservers + const ns = (rec.nameservers || []).map((n) => n.host.toLowerCase()); + assert.ok(ns.includes("a.iana-servers.net")); + assert.ok(ns.includes("b.iana-servers.net")); + if (c.expectDs) { + // DS records typically present for .com/.net + assert.equal(rec.dnssec?.enabled, true); + assert.ok((rec.dnssec?.dsRecords || []).length > 0); + } + }, + ); +} + +// RDAP-only negative: .io lacks RDAP; expect failure +(shouldRun ? test : test.skip)( + "RDAP-only lookup for example.io fails", + async () => { + const res = await lookupDomain("example.io", { + timeoutMs: 15000, + rdapOnly: true, + }); + assert.equal(res.ok, false); + }, +); + +// WHOIS-only smoke for example.com +(shouldRun ? test : test.skip)( + "WHOIS-only lookup for example.com", + async () => { + const res = await lookupDomain("example.com", { + timeoutMs: 15000, + whoisOnly: true, + followWhoisReferral: true, + }); + assert.equal(res.ok, true, res.error); + assert.equal(res.record?.tld, "com"); + assert.equal(res.record?.source, "whois"); + // Invariants for example.com + assert.equal( + res.record?.whoisServer?.toLowerCase(), + "whois.verisign-grs.com", + ); + assert.equal(res.record?.registrar?.ianaId, "376"); + const ns = (res.record?.nameservers || []).map((n) => n.host.toLowerCase()); + assert.ok(ns.includes("a.iana-servers.net")); + assert.ok(ns.includes("b.iana-servers.net")); + }, +); + +// WHOIS-only smoke for example.io (RDAP-incompatible TLD) +(shouldRun ? test : test.skip)("WHOIS-only lookup for example.io", async () => { + const res = await lookupDomain("example.io", { + timeoutMs: 15000, + whoisOnly: true, + followWhoisReferral: true, + }); + assert.equal(res.ok, true, res.error); + const rec = res.record!; + assert.equal(rec.tld, "io"); + assert.equal(rec.source, "whois"); + // Accept either TLD WHOIS or registrar WHOIS as the final server + const server = (rec.whoisServer || "").toLowerCase(); + assert.ok(["whois.nic.io", "whois.namecheap.com"].includes(server)); + // Registrar ID may only be present on registrar WHOIS responses + if (rec.registrar?.ianaId) { + assert.equal(rec.registrar.ianaId, "1068"); + } + // Nameservers commonly set for example.io (DigitalOcean) + const ns = (rec.nameservers || []).map((n) => n.host.toLowerCase()); + assert.ok(ns.includes("ns1.digitalocean.com")); + assert.ok(ns.includes("ns2.digitalocean.com")); + assert.ok(ns.includes("ns3.digitalocean.com")); +}); diff --git a/src/lib/__tests__/dates.test.ts b/src/lib/__tests__/dates.test.ts index 498c248..aacbceb 100644 --- a/src/lib/__tests__/dates.test.ts +++ b/src/lib/__tests__/dates.test.ts @@ -1,3 +1,5 @@ +/** biome-ignore-all lint/style/noNonNullAssertion: this is fine for tests */ + import assert from "node:assert/strict"; import test from "node:test"; import { toISO } from "../dates.js"; @@ -7,11 +9,9 @@ test("toISO parses ISO and common whois formats", () => { assert.equal(iso, "2023-01-02T03:04:05Z"); const noZ = toISO("2023-01-02 03:04:05"); - // biome-ignore lint/style/noNonNullAssertion: this is fine assert.match(noZ!, /^2023-01-02T03:04:05Z$/); const slash = toISO("2023/01/02 03:04:05"); - // biome-ignore lint/style/noNonNullAssertion: this is fine assert.match(slash!, /^2023-01-02T03:04:05Z$/); const dmy = toISO("02-Jan-2023");