Files

133 lines
4.1 KiB
TypeScript

import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { buildSearchUrl, parseCliRequest, runCli } from "../src/cli.js";
function createOutput() {
let stdout = "";
let stderr = "";
return {
stdout: { write: (chunk: string) => { stdout += chunk; return true; } },
stderr: { write: (chunk: string) => { stderr += chunk; return true; } },
get stdoutText() { return stdout; },
get stderrText() { return stderr; }
};
}
describe("amazon-shopping CLI", () => {
it("prints help", async () => {
const output = createOutput();
const code = await runCli(["--help"], output);
assert.equal(code, 0);
assert.match(output.stdoutText, /scripts\/search-products/);
assert.match(output.stdoutText, /--dry-run/);
});
it("defaults to 15 results and two search pages", () => {
const request = parseCliRequest(["usb c cable"]);
assert.equal(request.query, "usb c cable");
assert.equal(request.limit, 15);
assert.equal(request.maxSearchPages, 2);
assert.equal(request.output, "json");
});
it("maps kebab-case CLI filters into the request contract", () => {
const request = parseCliRequest([
"--query",
"100w led bulbs",
"--min-rating",
"4.5",
"--min-reviews",
"200",
"--max-unit-price",
"4",
"--min-width",
"77",
"--require-prime",
"--delivery-by",
"tomorrow",
"--sort-by",
"price",
"--max-search-pages",
"3",
"--skip-details",
"--dry-run"
]);
assert.equal(request.query, "100w led bulbs");
assert.equal(request.filters.minRating, 4.5);
assert.equal(request.filters.minReviews, 200);
assert.equal(request.filters.maxUnitPrice, 4);
assert.equal(request.filters.minWidthInches, 77);
assert.equal(request.filters.requirePrime, true);
assert.equal(request.filters.deliveryBy, "tomorrow");
assert.equal(request.filters.sortBy, "price");
assert.equal(request.maxSearchPages, 3);
assert.equal(request.skipDetails, true);
assert.equal(request.dryRun, true);
});
it("maps output modes", () => {
assert.equal(parseCliRequest(["usb c cable", "--json"]).output, "json");
assert.equal(parseCliRequest(["usb c cable", "--markdown"]).output, "markdown");
assert.equal(parseCliRequest(["usb c cable", "--json", "--markdown"]).output, "both");
});
it("accepts max as a natural agent alias for limit", () => {
const request = parseCliRequest(["100w led bulbs", "--max", "5"]);
assert.equal(request.limit, 5);
});
it("normalizes natural-language filters for the target request", () => {
const request = parseCliRequest([
"100w led bulbs that cost less than $4 each and have over 200 reviews with a review score of more than 4.5 stars",
"--dry-run"
]);
assert.equal(request.query, "100w led bulbs");
assert.equal(request.filters.maxUnitPrice, 4);
assert.equal(request.filters.minReviews, 200);
assert.equal(request.filters.reviewCountComparison, "gt");
assert.equal(request.filters.minRating, 4.5);
assert.equal(request.filters.ratingComparison, "gt");
});
it("rejects limits below one", () => {
assert.throws(
() => parseCliRequest(["usb c cable", "--limit", "0"]),
/limit must be an integer greater than 0/
);
});
it("rejects unsafe large limits unless explicitly allowed", () => {
assert.throws(
() => parseCliRequest(["usb c cable", "--limit", "31"]),
/require --allow-large-limit/
);
});
it("rejects search page caps above five", () => {
assert.throws(
() => parseCliRequest(["usb c cable", "--max-search-pages", "6"]),
/max-search-pages must be 5 or less/
);
});
it("rejects unsupported sort modes", () => {
assert.throws(
() => parseCliRequest(["usb c cable", "--sort-by", "rating"]),
/sort-by must be either price or relevance/
);
});
it("builds the Amazon search URL without live network access", () => {
assert.equal(
buildSearchUrl("100w led bulbs"),
"https://www.amazon.com/s?k=100w%20led%20bulbs"
);
});
});