Polish flight-finder PDF layout
This commit is contained in:
@@ -6,6 +6,7 @@ import fs from "node:fs";
|
||||
|
||||
import {
|
||||
describeQuoteBookingLinks,
|
||||
formatArtifactsRoot,
|
||||
renderFlightReportPdf,
|
||||
ReportValidationError
|
||||
} from "../src/report-pdf.js";
|
||||
@@ -63,6 +64,10 @@ function samplePayload(): FlightReportPayload {
|
||||
};
|
||||
}
|
||||
|
||||
function countPdfPages(outputPath: string): number {
|
||||
return fs.readFileSync(outputPath, "latin1").split("/Type /Page").length - 1;
|
||||
}
|
||||
|
||||
test("renderFlightReportPdf writes a non-empty PDF", async () => {
|
||||
const outputPath = path.join(os.tmpdir(), `flight-finder-${Date.now()}.pdf`);
|
||||
await renderFlightReportPdf(samplePayload(), outputPath);
|
||||
@@ -111,6 +116,81 @@ test("renderFlightReportPdf embeds booking links and only includes direct-airlin
|
||||
assert.doesNotMatch(pdfContents, /Direct airline booking: not captured in this run[\s\S]*https:\/\/example\.com\/quote-1/);
|
||||
});
|
||||
|
||||
test("renderFlightReportPdf avoids raw absolute artifact paths and keeps page count bounded for a long report", async () => {
|
||||
const outputPath = path.join(os.tmpdir(), `flight-finder-long-${Date.now()}.pdf`);
|
||||
const payload = samplePayload();
|
||||
payload.searchExecution.artifactsRoot =
|
||||
"/Users/stefano/.openclaw/workspace/reports/dfw-blq-flight-report-2026-03-30-fresh-185742";
|
||||
payload.quotes = [
|
||||
{
|
||||
...payload.quotes[0],
|
||||
id: "quote-1",
|
||||
notes: [
|
||||
"Observed on fresh KAYAK sweep at $794 per traveler for 3 adults.",
|
||||
"Skyscanner TH/USD corroborated the same Madrid pattern.",
|
||||
"Expedia also found a nearby fare band."
|
||||
]
|
||||
},
|
||||
{
|
||||
id: "quote-2",
|
||||
source: "kayak",
|
||||
legId: "return-pair",
|
||||
passengerGroupIds: ["pair"],
|
||||
bookingLink: "https://example.com/quote-2",
|
||||
itinerarySummary: "BLQ -> DFW via LHR",
|
||||
totalPriceUsd: 1316,
|
||||
displayPriceUsd: "$1,316 total ($658 pp x 2)",
|
||||
notes: [
|
||||
"Cheapest valid paired return captured in the fresh KAYAK sweep.",
|
||||
"Skyscanner did not reproduce the exact low Jun 8 return cleanly.",
|
||||
"Expedia hit a bot challenge on the Jun 8 paired-return check."
|
||||
]
|
||||
},
|
||||
{
|
||||
id: "quote-3",
|
||||
source: "kayak",
|
||||
legId: "return-solo",
|
||||
passengerGroupIds: ["solo"],
|
||||
bookingLink: "https://example.com/quote-3",
|
||||
itinerarySummary: "BLQ -> DFW via MAD",
|
||||
totalPriceUsd: 722,
|
||||
displayPriceUsd: "$722 total",
|
||||
notes: [
|
||||
"Lowest valid solo-return fare in the fresh Jul window capture.",
|
||||
"Skyscanner TH/USD showed the same Madrid connection at about $742.",
|
||||
"Expedia surfaced a cheaper Turkish option, but it was excluded."
|
||||
]
|
||||
}
|
||||
];
|
||||
payload.rankedOptions = [
|
||||
{
|
||||
id: "primary",
|
||||
title: "Best overall itinerary",
|
||||
quoteIds: ["quote-1", "quote-2", "quote-3"],
|
||||
totalPriceUsd: 4420,
|
||||
rationale: "Best price-to-convenience tradeoff."
|
||||
},
|
||||
{
|
||||
id: "backup",
|
||||
title: "Backup itinerary",
|
||||
quoteIds: ["quote-1", "quote-2", "quote-3"],
|
||||
totalPriceUsd: 4515,
|
||||
rationale: "Slightly higher price but still viable."
|
||||
}
|
||||
];
|
||||
payload.executiveSummary = [
|
||||
"Fresh Thailand-market sweeps shifted the outbound slightly earlier.",
|
||||
"Lowest valid total observed was $4,420.",
|
||||
"Cross-source corroboration is strongest for the outbound and solo return."
|
||||
];
|
||||
|
||||
await renderFlightReportPdf(payload, outputPath);
|
||||
|
||||
const pdfContents = fs.readFileSync(outputPath, "latin1");
|
||||
assert.doesNotMatch(pdfContents, /\/Users\/stefano\/\.openclaw\/workspace\/reports\//);
|
||||
assert.ok(countPdfPages(outputPath) <= 4);
|
||||
});
|
||||
|
||||
test("renderFlightReportPdf rejects incomplete report payloads", async () => {
|
||||
const outputPath = path.join(os.tmpdir(), `flight-finder-incomplete-${Date.now()}.pdf`);
|
||||
await assert.rejects(
|
||||
@@ -183,3 +263,11 @@ test("describeQuoteBookingLinks calls out missing direct-airline links explicitl
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
test("formatArtifactsRoot only shortens known workspace report paths", () => {
|
||||
assert.equal(
|
||||
formatArtifactsRoot("/Users/stefano/.openclaw/workspace/reports/dfw-blq-flight-report-2026-03-30-fresh-185742"),
|
||||
"reports/dfw-blq-flight-report-2026-03-30-fresh-185742"
|
||||
);
|
||||
assert.equal(formatArtifactsRoot("/tmp/run-123"), "run-123");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user