SERP API Contract Tests: A Client-Side QA Harness for Search Data Pipelines

By Serpent API Team··10 min read

Method note: Measurements in this article were run locally against authenticated Serpent API endpoints on August 3, 2026. Sample sizes are stated in the article. Treat the numbers as a dated field check, not a permanent guarantee.

Short answer: a contract test should prove your client can still read the public API response. It should not know anything about how the service is implemented. Check status, shape, required fields, and timestamps.

The examples below validate the public JSON contract for SERP API calls across engines. Keep these tests in your app or data pipeline so schema drift breaks in staging instead of in your dashboard.

Jest Contract Test

const BASE = process.env.SERPENT_BASE_URL || "https://apiserpent.com";
const KEY = process.env.SERPENT_API_KEY;

async function search(engine) {
  const url = new URL("/api/search/quick", BASE);
  url.searchParams.set("q", "weather today");
  url.searchParams.set("engine", engine);
  url.searchParams.set("country", "us");
  const res = await fetch(url, { headers: { "X-API-Key": KEY } });
  const body = await res.json();
  return { res, body };
}

test.each(["google", "bing", "yahoo", "ddg"])("%s public contract", async engine => {
  const { res, body } = await search(engine);
  expect([200, 429, 503]).toContain(res.status);
  if (res.status !== 200) return;
  expect(body.success).toBe(true);
  expect(body.engine).toBe(engine);
  expect(Array.isArray(body.results.organic)).toBe(true);
  expect(body.results.organic.length).toBeGreaterThan(0);
  for (const result of body.results.organic) {
    expect(result.title).toEqual(expect.any(String));
    expect(result.url).toMatch(/^https?:\/\//);
  }
});

Freshness Check

If the response has a timestamp, assert that it is recent enough for your job. If the status is 429 or 503, record the public status and schedule your own later attempt. Do not inspect private service behavior.

from datetime import datetime, timezone

def is_fresh(meta, max_age_minutes=15):
    stamp = meta.get("timestamp")
    if not stamp:
        return True
    seen = datetime.fromisoformat(stamp.replace("Z", "+00:00"))
    age = datetime.now(timezone.utc) - seen
    return age.total_seconds() <= max_age_minutes * 60

Pair this with SERP API observability if you need dashboards and alerts around the checks.

FAQ

What should a SERP API contract test check?

Check status, JSON shape, required fields, organic result count, URL validity, and timestamp freshness.

Should client tests know internal provider details?

No. Test the public contract only. Your client should not depend on implementation details.

How should 429 or 503 be handled?

Honor public response status and headers, record the event, and schedule the job for a later attempt from your own queue.

Related Posts