Documentation
    Preparing search index...
    • Validates search functionality by testing API results against manual filtering.

      Comprehensive search validation that samples entities from a complete dataset, extracts search values, applies manual filtering, calls the search API, and compares results. Validates that search APIs return the correct subset of data matching the search criteria.

      Processing cost: For K sampled entities from N entries, sparse sampling costs O(K), each reference filter scans N entries and each returned page prefix is compared once. Calls are sequential and one sample result is live at a time.

      Reuse: Each invocation must evaluate its supplied task or request to observe current behavior; prior results cannot replace these effectful checks.

      Resource ownership: The returned promise retains invocation-local state until settlement. The callback owns its external resources, and this validator provides no cancellation or timeout.

      Type Parameters

      • Entity extends IEntity<any>
      • Request

      Parameters

      • title: string

        Descriptive title used in error messages when search fails

      • getter: (input: Request) => Promise<Entity[]>

        API function that performs the search

      • total: Entity[]

        Complete dataset to sample from for testing

      • sampleCount: number = 1

        Number of random samples to test (default: 1)

      Returns <Values extends any[]>(
          props: ISearchProps<Entity, Values, Request>,
      ) => Promise<void>

      A function that accepts search configuration properties

      // Test article search functionality with exact matching
      const allArticles = await db.articles.findAll();
      const searchValidator = TestValidator.search(
      "article search API",
      (req) => api.searchArticles(req),
      allArticles,
      5, // test with 5 random samples
      );

      // Test exact match search
      await searchValidator({
      fields: ["title"],
      values: (article) => [article.title], // full title for exact match
      filter: (article, [title]) => article.title === title, // exact match
      request: ([title]) => ({ search: { title } }),
      });

      // Test partial match search with includes
      await searchValidator({
      fields: ["content"],
      values: (article) => [article.content.substring(0, 20)], // partial content
      filter: (article, [keyword]) => article.content.includes(keyword),
      request: ([keyword]) => ({ q: keyword }),
      });

      // Test multi-field search with exact matching
      await searchValidator({
      fields: ["writer", "title"],
      values: (article) => [article.writer, article.title],
      filter: (article, [writer, title]) =>
      article.writer === writer && article.title === title,
      request: ([writer, title]) => ({ search: { writer, title } }),
      });

      Error when API search results don't match manual filtering results

      contracts/common.md#principled-implementation A sample of entities is drawn, the search values are read from each, the expected set is computed by a manual filter over the whole dataset, the API is called with the request built from the values, and index compares the two lists, so the API is checked against a filter the test author wrote independently.

      contracts/common.md#clear-and-simple-design The function is curried so the dataset and the API are given once and each search configuration is run against them, and the comparison is delegated to index.

      contracts/common.md#prohibited-implementation-shortcuts The sample, values, filter, and request all come from the caller's configuration.

      contracts/common.md#meaningful-documentation The comment documents the steps, the parameters, and the thrown error, with examples.