fix: align marketplace price filter parsing
This commit is contained in:
@@ -38,7 +38,7 @@ export interface EbayListingDetails {
|
|||||||
address?: string | null;
|
address?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const EBAY_PRICE_TEXT_RE = /^(?:\s*(?:CA|C)\s*\$|\s*[$£€¥])/u;
|
const EBAY_PRICE_TEXT_RE = /^(?:\s*(?:CA|C|US)\s*\$|\s*[$£€¥])/u;
|
||||||
|
|
||||||
function canonicalizeEbayItemUrl(url: string): string {
|
function canonicalizeEbayItemUrl(url: string): string {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -218,6 +218,10 @@ function normalizeLookupKey(value: string): string {
|
|||||||
return value.toLowerCase().replace(/[\s-]+/g, "-");
|
return value.toLowerCase().replace(/[\s-]+/g, "-");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function centsToKijijiPriceParam(cents: number): number {
|
||||||
|
return Math.floor(cents / 100);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve location ID from name or return numeric ID
|
* Resolve location ID from name or return numeric ID
|
||||||
*/
|
*/
|
||||||
@@ -293,9 +297,13 @@ export function buildSearchUrl(
|
|||||||
: "relevancyDesc";
|
: "relevancyDesc";
|
||||||
const sortOrder = options.sortOrder === "asc" ? "ASC" : "DESC";
|
const sortOrder = options.sortOrder === "asc" ? "ASC" : "DESC";
|
||||||
const priceMinParam =
|
const priceMinParam =
|
||||||
typeof options.priceMin === "number" ? `&priceMin=${options.priceMin}` : "";
|
typeof options.priceMin === "number"
|
||||||
|
? `&priceMin=${centsToKijijiPriceParam(options.priceMin)}`
|
||||||
|
: "";
|
||||||
const priceMaxParam =
|
const priceMaxParam =
|
||||||
typeof options.priceMax === "number" ? `&priceMax=${options.priceMax}` : "";
|
typeof options.priceMax === "number"
|
||||||
|
? `&priceMax=${centsToKijijiPriceParam(options.priceMax)}`
|
||||||
|
: "";
|
||||||
const pageParam =
|
const pageParam =
|
||||||
options.page && options.page > 1 ? `&page=${options.page}` : "";
|
options.page && options.page > 1 ? `&page=${options.page}` : "";
|
||||||
|
|
||||||
|
|||||||
@@ -360,6 +360,39 @@ describe("eBay Scraper Cookie Handling", () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("prefers discounted US dollar prices over original prices", async () => {
|
||||||
|
global.fetch = mock(() =>
|
||||||
|
Promise.resolve({
|
||||||
|
ok: true,
|
||||||
|
text: () =>
|
||||||
|
Promise.resolve(`
|
||||||
|
<html><body>
|
||||||
|
<li class="s-item">
|
||||||
|
<a href="/itm/123"></a>
|
||||||
|
<h3>Stable Laptop Bundle</h3>
|
||||||
|
<span class="s-item__price">
|
||||||
|
<s>US $150.00</s>
|
||||||
|
<span>US $100.00</span>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</body></html>
|
||||||
|
`),
|
||||||
|
}),
|
||||||
|
) as typeof fetch;
|
||||||
|
|
||||||
|
const results = await fetchEbayItems("laptop", 1000);
|
||||||
|
|
||||||
|
expect(results).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
listingPrice: expect.objectContaining({
|
||||||
|
amountFormatted: "US $100.00",
|
||||||
|
cents: 10000,
|
||||||
|
currency: "USD",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
test("accepts higher fallback prices without price classes", async () => {
|
test("accepts higher fallback prices without price classes", async () => {
|
||||||
global.fetch = mock(() =>
|
global.fetch = mock(() =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
|
|||||||
@@ -163,8 +163,8 @@ describe("URL Construction", () => {
|
|||||||
priceMax: 10000,
|
priceMax: 10000,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(url).toContain("priceMin=8000");
|
expect(url).toContain("priceMin=80");
|
||||||
expect(url).toContain("priceMax=10000");
|
expect(url).toContain("priceMax=100");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should handle string location/category inputs", () => {
|
test("should handle string location/category inputs", () => {
|
||||||
@@ -570,7 +570,7 @@ describe("fetchKijijiItems", () => {
|
|||||||
global.fetch = mock((input: string | URL | Request) => {
|
global.fetch = mock((input: string | URL | Request) => {
|
||||||
const url = typeof input === "string" ? input : input.toString();
|
const url = typeof input === "string" ? input : input.toString();
|
||||||
|
|
||||||
if (url.includes("/k0c0l1700272") && url.includes("priceMin=8000")) {
|
if (url.includes("/k0c0l1700272") && url.includes("priceMin=80")) {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
ok: true,
|
ok: true,
|
||||||
text: () => Promise.resolve(searchHtml),
|
text: () => Promise.resolve(searchHtml),
|
||||||
@@ -672,7 +672,7 @@ describe("fetchKijijiItems", () => {
|
|||||||
global.fetch = mock((input: string | URL | Request) => {
|
global.fetch = mock((input: string | URL | Request) => {
|
||||||
const url = typeof input === "string" ? input : input.toString();
|
const url = typeof input === "string" ? input : input.toString();
|
||||||
|
|
||||||
if (url.includes("/k0c0l1700272") && url.includes("priceMin=8000") && url.includes("priceMax=15000")) {
|
if (url.includes("/k0c0l1700272") && url.includes("priceMin=80") && url.includes("priceMax=150")) {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
ok: true,
|
ok: true,
|
||||||
text: () => Promise.resolve(searchHtml),
|
text: () => Promise.resolve(searchHtml),
|
||||||
|
|||||||
Reference in New Issue
Block a user