fix: clear price to null when a comparison finds no merchant offer
Several memory sticks (e.g. Crucial CT8G48C40U5, Patriot Signature Line,
Kingston FURY Beast) kept displaying their pc-builder.io catalog price
("€35.99", "€39.99"...) even after clicking "Compare prices" and getting
"No live price found, using catalog price" - an unconfirmed number was
being shown as if it were still valid, which is misleading given
pc-builder.io's catalog is known to go stale (see the earlier RTX 5070
€128 vs €66.89 case).
New clearPriceIfNoOffers(): when ScrapedPartsController#compare finds
zero offers across all 7 supported merchants, the part's price/priceSource
are reset to null, regardless of whether the price previously came from
the pc-builder.io catalog or an earlier verified merchant match - per
explicit product decision, an empty comparison always wins over keeping a
possibly-stale number around.
- ScrapedPartsController#compare now calls clearPriceIfNoOffers() in the
empty-offers branch, and returns the resulting price in the JSON
response so the frontend can mirror it exactly
- NewPartSearch.vue: comparePrices() now sets part.price from the
response's `price` field (mirroring exactly what the backend just
persisted) instead of only updating it on a cheaper find; removed the
now-inaccurate "using catalog price €X" message since that price no
longer exists once compared with no result
- 3 new tests for clearPriceIfNoOffers: clears an unverified
pc-builder.io price, also clears a previously-verified merchant price
when no longer confirmed, and is a no-op when there was no price to
begin with
Verified end-to-end against the reported Crucial CT8G48C40U5 example:
price went from 35.99 (pc-builder.io) to null after a real comparison
found zero matching offers on any merchant.
This commit is contained in:
1 parent
fa74791c92
commit
0ce6a7f4a7
4 files changed
+96
-19
No files matched your search
@@ -7,6 +7,7 @@ import {
|
||||
isCategoryStale,
|
||||
ensureFreshCategory,
|
||||
updatePriceIfCheaper,
|
||||
clearPriceIfNoOffers,
|
||||
shouldKeepExistingPrice,
|
||||
CACHE_TTL_HOURS,
|
||||
} from '#services/part_scraper_service'
|
||||
@@ -217,6 +218,53 @@ test.group('Best-known-price persistence', () => {
|
||||
})
|
||||
})
|
||||
|
||||
test.group('clearPriceIfNoOffers', () => {
|
||||
test('clears an unverified pc-builder.io catalog price when no merchant confirms it', async ({
|
||||
assert,
|
||||
}) => {
|
||||
// Regression: memory sticks kept showing pc-builder.io catalog prices
|
||||
// (e.g. €35.99) even though comparing prices found no matching offer
|
||||
// on any merchant ("No live price found, using catalog price €35.99")
|
||||
// — an unconfirmed number should not be displayed as if it were still
|
||||
// valid.
|
||||
const type = await createType('Memory-clear-1')
|
||||
const part = await createScrapedPart(type.id, 'ZZZ-Test-Clear-A', 'clear-a-p1', 35.99)
|
||||
|
||||
await clearPriceIfNoOffers(part)
|
||||
await part.refresh()
|
||||
|
||||
assert.isNull(part.price)
|
||||
assert.isNull(part.priceSource)
|
||||
})
|
||||
|
||||
test('also clears a price previously verified by a merchant if no longer confirmed', async ({
|
||||
assert,
|
||||
}) => {
|
||||
const type = await createType('Memory-clear-2')
|
||||
const part = await createScrapedPart(type.id, 'ZZZ-Test-Clear-B', 'clear-b-p1', 50)
|
||||
part.priceSource = 'LDLC'
|
||||
await part.save()
|
||||
|
||||
await clearPriceIfNoOffers(part)
|
||||
await part.refresh()
|
||||
|
||||
assert.isNull(part.price)
|
||||
assert.isNull(part.priceSource)
|
||||
})
|
||||
|
||||
test('is a no-op when the part already has no price', async ({ assert }) => {
|
||||
const type = await createType('Memory-clear-3')
|
||||
const part = await createScrapedPart(type.id, 'ZZZ-Test-Clear-C', 'clear-c-p1', null)
|
||||
const originalCheckedAt = part.priceCheckedAt
|
||||
|
||||
await clearPriceIfNoOffers(part)
|
||||
await part.refresh()
|
||||
|
||||
assert.isNull(part.price)
|
||||
assert.equal(part.priceCheckedAt, originalCheckedAt)
|
||||
})
|
||||
})
|
||||
|
||||
test.group('Catalog refresh price protection (shouldKeepExistingPrice)', () => {
|
||||
test('an unverified pc-builder.io price is NOT protected and gets overwritten', ({ assert }) => {
|
||||
// Regression test: a GPU had price=431.17 from a previous pc-builder.io
|
||||
|
||||
Reference in new issue
Block a user