Initial commit: Price Hunter — self-hosted price comparison engine
Complete application scaffolding with: - Backend: Node.js + Fastify + sql.js (SQLite) - Frontend: SvelteKit + Tailwind CSS - Scraper engine with parallel fan-out, rate limiting, cheerio-based parsing - Store management with CSS selector config and per-store test pages - Docker setup for single-command deployment Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
51
tests/server/scraper/result-parser.test.ts
Normal file
51
tests/server/scraper/result-parser.test.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { parsePrice, normalizeUrl } from '../../../src/server/scraper/result-parser.js';
|
||||
|
||||
describe('parsePrice', () => {
|
||||
it('parses US format prices', () => {
|
||||
expect(parsePrice('$12.99')).toBe(12.99);
|
||||
expect(parsePrice('$1,299.00')).toBe(1299);
|
||||
expect(parsePrice('$0.50')).toBe(0.5);
|
||||
});
|
||||
|
||||
it('parses European format prices', () => {
|
||||
expect(parsePrice('€12,99')).toBe(12.99);
|
||||
expect(parsePrice('1.299,00 EUR')).toBe(1299);
|
||||
expect(parsePrice('€299,99')).toBe(299.99);
|
||||
});
|
||||
|
||||
it('handles free', () => {
|
||||
expect(parsePrice('free')).toBe(0);
|
||||
expect(parsePrice('FREE')).toBe(0);
|
||||
expect(parsePrice('gratis')).toBe(0);
|
||||
});
|
||||
|
||||
it('handles price ranges', () => {
|
||||
expect(parsePrice('$12 - $15')).toBe(12);
|
||||
expect(parsePrice('€10,00 – €20,00')).toBe(10);
|
||||
});
|
||||
|
||||
it('handles plain numbers', () => {
|
||||
expect(parsePrice('42')).toBe(42);
|
||||
expect(parsePrice('12.99')).toBe(12.99);
|
||||
});
|
||||
|
||||
it('returns null for invalid input', () => {
|
||||
expect(parsePrice('')).toBe(null);
|
||||
expect(parsePrice('abc')).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('normalizeUrl', () => {
|
||||
it('returns absolute URLs as-is', () => {
|
||||
expect(normalizeUrl('https://example.com/product', 'https://base.com')).toBe('https://example.com/product');
|
||||
});
|
||||
|
||||
it('resolves relative URLs against base', () => {
|
||||
expect(normalizeUrl('/products/123', 'https://store.com')).toBe('https://store.com/products/123');
|
||||
});
|
||||
|
||||
it('returns base URL for empty href', () => {
|
||||
expect(normalizeUrl('', 'https://store.com')).toBe('https://store.com');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user