Skip to content

test: provider conformance testkit + weekly live smoke against real APIs#11

Merged
MyPrototypeWhat merged 7 commits into
mainfrom
m13t/wave3-test-infrastructure
Jul 6, 2026
Merged

test: provider conformance testkit + weekly live smoke against real APIs#11
MyPrototypeWhat merged 7 commits into
mainfrom
m13t/wave3-test-infrastructure

Conversation

@MyPrototypeWhat

Copy link
Copy Markdown
Owner

Summary

Wave 3 of the hardening plan (test infrastructure):

  • @refkit/provider-testkit (private, unpublished): searchConformant encodes the provider-conformance rules (schema validity, provider id stamping, licenseVersion-only-on-CC-families, D8 no-landing-page-as-media) as reusable assertions; expectLicenseMap for data-driven license-mapping checks. Adopted in openverse + europeana as proof.
  • Live smoke: 22 env-gated suites across all 18 provider packages (REFKIT_LIVE=1; BYOK suites additionally key-gated) reuse the same conformance assertions against real APIs — upstream drift becomes visible instead of silent. Default pnpm test:run stays fully hermetic (verified: zero live suites selected without the env).
  • Weekly cron (.github/workflows/live-smoke.yml, Mondays 03:17 UTC + manual dispatch, read-only permissions): keyless providers always; BYOK when repo secrets exist.

No changesets: testkit is private, live suites/workflow are dev-only, and provider devDependency additions don't change published artifacts (verified against files whitelists).

Test Plan

  • pnpm test:run — 304 passed / 22 skipped (hermetic; zero regressions)
  • pnpm -r typecheck — all packages clean
  • Real spot check: REFKIT_LIVE=1 against live Met + PoetryDB APIs — 8/8 green
  • Review-verified: D8 rule calibrated against real CDN thumbnail shapes (openverse/smithsonian/unsplash), BYOK gating truth table, no phantom deps, frozen-lockfile install clean

Add @refkit/provider-testkit (private, workspace-only) with
searchConformant() and expectLicenseMap(): reusable assertions that run a
provider's search through fixture or live fetch and check schema validity,
id/providerId identify the provider, licenseVersion is only on CC-family
licenses, and D8 image-URL rules for image providers.

id-rule: settled on exact prefix match `ref.id.startsWith(`${provider.id}:`)`
plus `ref.source.providerId === provider.id`, dropping the plan draft's OR
fallback — verified every current provider factory (including dual-factory
packages like openverse/openverse-audio, pexels/pexels-video,
pixabay/pixabay-video, polyhaven/ambientcg) stamps referenceId(providerId, …)
and source.providerId with the exact same string as provider.id, so the
exact match is sufficient and still catches a provider stamping the wrong
provider's id.

Also registers packages/provider-testkit/vitest.config.ts in the root
aggregator (vitest.config.ts enumerates package paths explicitly).
…l checks; field-wise license map compare

- D8 thumbnail: fail only when the thumbnail reuses the item's landing page
  (=== canonicalUrl or === source.sourceUrl); extensionless CDN thumbnails
  (openverse /thumb/, smithsonian deliveryService, unsplash query-param URLs)
  no longer false-fail — isLikelyImageUrl is now only a fast-accept, never a
  failure condition. Verified the REAL openverse factory + its real fixture
  passes searchConformant (would have thrown before this fix).
- Preview rule unchanged: image providers must declare image/* mediaType.
- Add negative self-tests for the previously unguarded checks: foreign id
  prefix, source.providerId mismatch, text/html preview mediaType; plus a
  passing extensionless-CDN thumbnail case.
- expectLicenseMap: replace key-order-sensitive JSON.stringify equality with
  field-wise compare (license+version exact; jurisdiction only when the
  expectation specifies it), widen case type to mapRightsUrl's shape, and add
  self-tests for key-order insensitivity and jurisdiction handling.
- JSDoc caveat on enforceImageUrls for mixed-modality factories.
Add packages/provider-testkit/src/live.ts exporting liveSmoke(), an env-gated
describe.skipIf wrapper around searchConformant() that runs one real query
against the live API (30s timeout) and asserts refs.length > 0. Exported via
a separate "./live" package export so consuming test files import from
'@refkit/provider-testkit/live', keeping vitest out of the main entry.

Add src/__tests__/live.test.ts to all 18 provider packages:
keyless (met, artic, wikimedia-commons, openverse+openverse-audio, gutendex,
poetrydb, rijksmuseum, polyhaven+ambientcg, internet-archive) and BYOK
(unsplash/UNSPLASH_KEY, pexels+pexels-video/PEXELS_KEY,
pixabay+pixabay-video/PIXABAY_KEY, flickr/FLICKR_KEY, smithsonian/SI_KEY,
brave/BRAVE_TOKEN, freesound/FREESOUND_TOKEN, jamendo/JAMENDO_CLIENT_ID,
europeana/EUROPEANA_KEY), matching packages/mcp/src/cli.ts's defaultProviders
construction exactly. Text providers (gutendex, poetrydb) use query 'love'.

Add @refkit/provider-testkit devDependency to every touched package still
missing it, plus vitest as a direct dependency of provider-testkit (live.ts
imports it). Root package.json gets a test:live script
(REFKIT_LIVE=1 vitest run).

Carry-over from W3.2 review: hoist europeana's inline pageOnly fixture to
module scope (ITEM_PAGE_ONLY) and include it in the conformance test's
fixture array, exercising the landing-page-rejection path. europeana keeps
page-only items via their thumbnail (not dropped), so the count assertion
holds unchanged.

Hermetic default (pnpm test:run): 304 passed, 22 new skipped (live suites),
totals otherwise unchanged. Spot-checked REFKIT_LIVE=1 against the real met
and poetrydb APIs — both green.
No changeset: testkit is private, live suites and the workflow are dev-only,
and provider devDependency additions do not change published artifacts.
@MyPrototypeWhat MyPrototypeWhat merged commit 09d309a into main Jul 6, 2026
1 check passed
@MyPrototypeWhat MyPrototypeWhat deleted the m13t/wave3-test-infrastructure branch July 6, 2026 10:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant