import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test"; import { extractApolloState, parseDetailedListing, parseSearch, } from "../src/kijiji"; // Mock fetch globally const originalFetch = global.fetch; describe("HTML Parsing Integration", () => { beforeEach(() => { // Mock fetch for all tests global.fetch = mock(() => { throw new Error("fetch should be mocked in individual tests"); }); }); afterEach(() => { global.fetch = originalFetch; }); describe("extractApolloState", () => { test("should extract Apollo state from valid HTML", () => { const mockHtml = ''; const result = extractApolloState(mockHtml); expect(result).toEqual({ ROOT_QUERY: { test: "value" }, }); }); test("should return null for HTML without Apollo state", () => { const mockHtml = "No data here"; const result = extractApolloState(mockHtml); expect(result).toBeNull(); }); test("should return null for malformed JSON", () => { const mockHtml = ''; const result = extractApolloState(mockHtml); expect(result).toBeNull(); }); test("should handle missing __NEXT_DATA__ element", () => { const mockHtml = "
Content
"; const result = extractApolloState(mockHtml); expect(result).toBeNull(); }); }); describe("parseSearch", () => { test("should parse search results from HTML", () => { const mockHtml = ` `; const results = parseSearch(mockHtml, "https://www.kijiji.ca"); expect(results).toHaveLength(2); expect(results[0]).toEqual({ name: "iPhone 13 Pro", listingLink: "https://www.kijiji.ca/v-iphone/k0l0", }); expect(results[1]).toEqual({ name: "Samsung Galaxy", listingLink: "https://www.kijiji.ca/v-samsung/k0l0", }); }); test("should handle absolute URLs", () => { const mockHtml = ` `; const results = parseSearch(mockHtml, "https://www.kijiji.ca"); expect(results[0].listingLink).toBe( "https://www.kijiji.ca/v-iphone/k0l0", ); }); test("should filter out invalid listings", () => { const mockHtml = ` `; const results = parseSearch(mockHtml, "https://www.kijiji.ca"); expect(results).toHaveLength(1); expect(results[0].name).toBe("iPhone 13 Pro"); }); test("should return empty array for invalid HTML", () => { const results = parseSearch( "Invalid", "https://www.kijiji.ca", ); expect(results).toEqual([]); }); }); describe("parseDetailedListing", () => { test("should parse detailed listing with all fields", async () => { const mockHtml = ` `; const result = await parseDetailedListing( mockHtml, "https://www.kijiji.ca", ); expect(result).toEqual({ url: "https://www.kijiji.ca/v-iphone-13-pro/k0l0", title: "iPhone 13 Pro 256GB", description: "Excellent condition iPhone 13 Pro", listingPrice: { amountFormatted: "$800.00", cents: 80000, currency: "CAD", }, listingType: "OFFER", listingStatus: "ACTIVE", creationDate: "2024-01-15T10:00:00.000Z", endDate: "2025-01-15T10:00:00.000Z", numberOfViews: 150, address: "Toronto, ON", images: [ "https://media.kijiji.ca/api/v1/image1.jpg", "https://media.kijiji.ca/api/v1/image2.jpg", ], categoryId: 132, adSource: "ORGANIC", flags: { topAd: false, priceDrop: true, }, attributes: { forsaleby: ["ownr"], phonecarrier: ["unlocked"], }, location: { id: 1700273, name: "Toronto", coordinates: { latitude: 43.6532, longitude: -79.3832, }, }, sellerInfo: { posterId: "user123", rating: 4.8, }, }); }); test("should return null for contact-based pricing", async () => { const mockHtml = ` `; const result = await parseDetailedListing( mockHtml, "https://www.kijiji.ca", ); expect(result).toBeNull(); }); test("should handle missing optional fields", async () => { const mockHtml = ` `; const result = await parseDetailedListing( mockHtml, "https://www.kijiji.ca", ); expect(result).toEqual({ url: "https://www.kijiji.ca/v-iphone/k0l0", title: "iPhone 13", description: undefined, listingPrice: { amountFormatted: "$500.00", cents: 50000, currency: undefined, }, listingType: undefined, listingStatus: undefined, creationDate: undefined, endDate: undefined, numberOfViews: undefined, address: null, images: [], categoryId: 0, adSource: "UNKNOWN", flags: { topAd: false, priceDrop: false, }, attributes: {}, location: { id: 0, name: "Unknown", coordinates: undefined, }, sellerInfo: undefined, }); }); }); });