SPB Git forge

spb/rareindex

Public
54commits 1branches 0releases
7.1 MBsize
maindefault branch
10 days agolast push
TypeScript 61.9% HTML 37.2% SQL 0.7%
3.1 KB · 57 lines typescript
Raw Blame History
1import { describe, expect, it } from 'vitest';2import metaJson from './meta.json' with { type: 'json' };3import { loadFixture, runFixtureSuite } from '@rareindex/connectors/testing';4import { missingRequirements } from '@rareindex/connectors';5import { localMeta } from '../_lib/local-meta.js';6import createConnector, { parseSearchResponse, priceOf, resolveTaxonomyPath, searchUrl } from './index.js';78const meta = localMeta(metaJson);9const connector = createConnector(meta);1011describe('etsy (gated)', () => {12  runFixtureSuite(connector, it, expect);1314  it('is gated on ETSY_API_KEY', () => {15    expect(meta.requires).toEqual(['ETSY_API_KEY']);16    expect(missingRequirements(meta, {})).toEqual(['ETSY_API_KEY']);17    expect(missingRequirements(meta, { ETSY_API_KEY: 'k' })).toEqual([]);18  });1920  it('builds findAllListingsActive URLs and resolves taxonomy paths', () => {21    const url = new URL(searchUrl({ keywords: 'vintage fountain pen', categorySlug: 'pens', minPrice: 50 }, { limit: 100, offset: 200, sortOn: 'created', sortOrder: 'desc' }, 1234));22    expect(url.origin + url.pathname).toBe('https://openapi.etsy.com/v3/application/listings/active');23    expect(url.searchParams.get('keywords')).toBe('vintage fountain pen');24    expect(url.searchParams.get('taxonomy_id')).toBe('1234');25    expect(url.searchParams.get('min_price')).toBe('50');26    expect(url.searchParams.get('limit')).toBe('100');27    expect(url.searchParams.get('offset')).toBe('200');28    const tree = { count: 1, results: [{ id: 1, name: 'Toys & Games', children: [{ id: 10, name: 'Games & Puzzles', children: [{ id: 100, name: 'Card Games', children: [] }] }] }] };29    expect(resolveTaxonomyPath(tree, ['Toys & Games', 'Games & Puzzles', 'Card Games'])).toBe(100);30    expect(resolveTaxonomyPath(tree, ['toys & games'])).toBe(1);31    expect(resolveTaxonomyPath(tree, ['Nope'])).toBeNull();32  });3334  it('parses Money prices (amount/divisor) and normalises native-currency listings', async () => {35    expect(priceOf({ amount: 12999, divisor: 100, currency_code: 'USD' })).toBe(129.99);36    expect(priceOf({ amount: 0, divisor: 100, currency_code: 'USD' })).toBeNull();37    const fx = loadFixture('etsy', 'docs-listings-active');38    const payload = fx.raw.payload as { listings: unknown[] };39    const parsed = parseSearchResponse({ count: 3, results: payload.listings });40    expect(parsed?.listings.length).toBe(payload.listings.length);41    expect(parseSearchResponse({ error: 'Invalid API key' })).toBeNull();42    const out = await connector.normalize(fx.raw);43    // one made_to_order listing is skipped44    expect(out.length).toBe(payload.listings.length - 1);45    const first = out[0]!;46    if (first.kind !== 'listing') throw new Error('expected listing');47    expect(first.currency).toBe('USD');48    expect(first.price).toBe(129.99);49    expect(first.attributes.identifiers.etsy_listing_id).toMatch(/^\d+$/);50    expect(first.imageUrls[0]).toMatch(/etsystatic/);51    expect(first.seller).toBeTruthy();52    expect(first.listedAt?.getUTCFullYear()).toBe(2026);53    const gbp = out.find((r) => r.kind === 'listing' && r.currency === 'GBP');54    expect(gbp).toBeTruthy();55  });56});57