@nestia/e2e 14.0.1 → 14.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,18 +11,31 @@
11
11
  * maintain currying patterns for advanced composition. All provide detailed
12
12
  * error messages for debugging failed assertions.
13
13
  *
14
+ * Processing cost: Scalar assertions use constant bookkeeping; JSON assertions
15
+ * traverse the expected structure, index compares the shared page prefix,
16
+ * search scans the dataset once per sample and sort checks adjacent results.
17
+ * External callbacks own their computation costs.
18
+ *
14
19
  * @author Jeongho Nam - https://github.com/samchon
15
20
  * @example
16
- * ```typescript
17
21
  * // Basic condition testing
18
- * TestValidator.predicate("user should be authenticated", user.isAuthenticated);
22
+ * TestValidator.predicate(
23
+ * "user should be authenticated",
24
+ * user.isAuthenticated,
25
+ * );
19
26
  *
20
27
  * // Equality validation
21
28
  * TestValidator.equals("API response should match expected", x, y);
22
29
  *
23
30
  * // Error validation
24
- * TestValidator.error("should throw on invalid input", () => assertInput(""));
25
- * ```;
31
+ * TestValidator.error("should throw on invalid input", () =>
32
+ * assertInput(""),
33
+ * );
34
+ *
35
+ * @evidence contracts/common.md#principled-implementation Each validator runs a check and throws an `Error` whose message begins with `Bug on <title>`, returning a promise only when its input is asynchronous, so the same function serves synchronous and asynchronous tests; the comparison helpers read values through their JSON form, which is the form an HTTP API delivers.
36
+ * @evidence contracts/common.md#clear-and-simple-design One function per assertion kind, sharing the JSON comparison (`json_equal_to`) and two small module helpers (`is_promise` and `is_sorted`), with the curried forms only where a request must be prepared once and run twice.
37
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Assertions compare the values they are given; none consults a fixture, an entity name, or an environment.
38
+ * @evidence contracts/common.md#meaningful-documentation The namespace prose lists the assertion families and the error message convention, with examples.
26
39
  */
27
40
  export declare namespace TestValidator {
28
41
  /**
@@ -32,19 +45,33 @@ export declare namespace TestValidator {
32
45
  * boolean, and asynchronous functions returning Promise<boolean>. The return
33
46
  * type is automatically inferred based on the input type.
34
47
  *
48
+ * Processing cost: The condition is evaluated once and asynchronous
49
+ * settlement adds constant bookkeeping without polling or repeating the
50
+ * condition.
51
+ *
52
+ * Reuse: Each invocation must evaluate its supplied task or request to
53
+ * observe current behavior; prior results cannot replace these effectful
54
+ * checks.
55
+ *
56
+ * Resource ownership: The returned promise retains invocation-local state
57
+ * until settlement. The callback owns its external resources, and this
58
+ * validator provides no cancellation or timeout.
59
+ *
35
60
  * @example
36
- * ```typescript
37
61
  * // Synchronous boolean
38
62
  * TestValidator.predicate("user should exist", user !== null);
39
63
  *
40
64
  * // Synchronous function
41
- * TestValidator.predicate("array should be empty", () => arr.length === 0);
65
+ * TestValidator.predicate(
66
+ * "array should be empty",
67
+ * () => arr.length === 0,
68
+ * );
42
69
  *
43
70
  * // Asynchronous function
44
- * await TestValidator.predicate("database should be connected",
45
- * async () => await db.ping()
71
+ * await TestValidator.predicate(
72
+ * "database should be connected",
73
+ * async () => await db.ping(),
46
74
  * );
47
- * ```;
48
75
  *
49
76
  * @param title - Descriptive title used in error messages when validation
50
77
  * fails
@@ -52,35 +79,54 @@ export declare namespace TestValidator {
52
79
  * function)
53
80
  * @returns Void or Promise<void> based on the input type
54
81
  * @throws Error with descriptive message when condition is not satisfied
82
+ * @evidence contracts/common.md#principled-implementation A boolean, a function returning a boolean, or a function returning a promise of a boolean is evaluated, and only the exact value `true` passes; a false result throws the same `Error` in all three forms, and the asynchronous form rejects with it.
83
+ * @evidence contracts/common.md#clear-and-simple-design One function whose three branches differ only in when the value is available.
84
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The check is on the value the caller gives, with no truthiness coercion.
85
+ * @evidence contracts/common.md#meaningful-documentation The comment documents the three forms, the parameters, the return type rule, and the thrown error, with examples.
55
86
  */
56
87
  function predicate<T extends boolean | (() => boolean) | (() => Promise<boolean>)>(title: string, condition: T): T extends () => Promise<boolean> ? Promise<void> : void;
57
88
  /**
58
89
  * Validates deep equality between two values using JSON comparison.
59
90
  *
60
- * Performs recursive comparison of objects and arrays. Supports an optional
91
+ * Performs recursive comparison of objects and arrays through their JSON
92
+ * form. The comparison walks the keys of the first value, so a key that only
93
+ * the second value has is ignored, which is why the second value may be a
94
+ * subtype of the first. Keys whose value in the first value is `undefined`
95
+ * are skipped, and arrays must have the same length. Supports an optional
61
96
  * exception filter to ignore specific keys during comparison. Useful for
62
97
  * validating API responses, data transformations, and object state changes.
63
98
  *
99
+ * Processing cost: The shared JSON walker traverses the first value and its
100
+ * corresponding second-value positions once, with recursion and accessor
101
+ * output proportional to visited structure; serialization occurs only on
102
+ * failure.
103
+ *
64
104
  * @example
65
- * ```typescript
66
105
  * // Basic equality
67
- * TestValidator.equals("response should match expected", expectedUser, actualUser);
106
+ * TestValidator.equals(
107
+ * "response should match expected",
108
+ * expectedUser,
109
+ * actualUser,
110
+ * );
68
111
  *
69
112
  * // Ignore timestamps in comparison
70
- * TestValidator.equals("user data should match", expectedUser, actualUser,
71
- * (key) => key === "updatedAt"
113
+ * TestValidator.equals(
114
+ * "user data should match",
115
+ * expectedUser,
116
+ * actualUser,
117
+ * (key) => key === "updatedAt",
72
118
  * );
73
119
  *
74
120
  * // Validate API response structure
75
- * TestValidator.equals("API response structure",
121
+ * TestValidator.equals(
122
+ * "API response structure",
123
+ * { id: 1, name: "John" },
76
124
  * { id: 1, name: "John" },
77
- * { id: 1, name: "John" }
78
125
  * );
79
126
  *
80
127
  * // Type-safe nullable comparisons
81
128
  * const nullableData: { name: string } | null = getData();
82
129
  * TestValidator.equals("nullable check", nullableData, null);
83
- * ```;
84
130
  *
85
131
  * @param title - Descriptive title used in error messages when values differ
86
132
  * @param X - The first value to compare
@@ -88,33 +134,52 @@ export declare namespace TestValidator {
88
134
  * @param exception - Optional filter function to exclude specific keys from
89
135
  * comparison
90
136
  * @throws Error with detailed diff information when values are not equal
137
+ * @evidence contracts/common.md#principled-implementation Both values are compared through `json_equal_to`, which walks the keys of the first value, so the second value may carry extra keys and the typing `Y extends X` states that; the differing accessors are listed in the error with both values serialized.
138
+ * @evidence contracts/common.md#clear-and-simple-design A thin wrapper over the shared comparison that adds the message.
139
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The exception filter is the caller's; the function contains no key name of its own.
140
+ * @evidence contracts/common.md#meaningful-documentation The comment states the JSON form, the key-walking rule with its consequence for extra keys, the array length rule, and the exception filter, with examples.
91
141
  */
92
142
  function equals<X, Y extends X = X>(title: string, X: X, y: Y | null | undefined, exception?: (key: string) => boolean): void;
93
143
  /**
94
144
  * Validates deep inequality between two values using JSON comparison.
95
145
  *
96
146
  * Performs recursive comparison of objects and arrays to ensure they are NOT
97
- * equal. Supports an optional exception filter to ignore specific keys during
98
- * comparison. Useful for validating that data has changed, objects are
147
+ * equal, by the same rules as {@link equals}: only the keys of the first value
148
+ * are compared, so a key that only the second value has does not make them
149
+ * different. Supports an optional exception filter to ignore specific keys
150
+ * during comparison. Useful for validating that data has changed, objects are
99
151
  * different, or mutations have occurred.
100
152
  *
153
+ * Processing cost: The shared JSON walker visits the first value and
154
+ * corresponding positions once; a failure additionally serializes both values
155
+ * for diagnostics. Space follows visited structure and reported differences.
156
+ *
101
157
  * @example
102
- * ```typescript
103
158
  * // Basic inequality
104
- * TestValidator.notEquals("user should be different after update", originalUser, updatedUser);
159
+ * TestValidator.notEquals(
160
+ * "user should be different after update",
161
+ * originalUser,
162
+ * updatedUser,
163
+ * );
105
164
  *
106
165
  * // Ignore timestamps in comparison
107
- * TestValidator.notEquals("user data should differ", originalUser, modifiedUser,
108
- * (key) => key === "updatedAt"
166
+ * TestValidator.notEquals(
167
+ * "user data should differ",
168
+ * originalUser,
169
+ * modifiedUser,
170
+ * (key) => key === "updatedAt",
109
171
  * );
110
172
  *
111
173
  * // Validate state changes
112
- * TestValidator.notEquals("state should have changed", initialState, currentState);
174
+ * TestValidator.notEquals(
175
+ * "state should have changed",
176
+ * initialState,
177
+ * currentState,
178
+ * );
113
179
  *
114
180
  * // Type-safe nullable comparisons
115
181
  * const mutableData: { count: number } | null = getMutableData();
116
182
  * TestValidator.notEquals("should have changed", mutableData, null);
117
- * ```;
118
183
  *
119
184
  * @param title - Descriptive title used in error messages when values are
120
185
  * equal
@@ -123,6 +188,10 @@ export declare namespace TestValidator {
123
188
  * @param exception - Optional filter function to exclude specific keys from
124
189
  * comparison
125
190
  * @throws Error when values are equal (indicating validation failure)
191
+ * @evidence contracts/common.md#principled-implementation It runs the same comparison as `equals` and fails when the comparison finds no difference, so two values differing only by extra keys of the second are considered equal and fail.
192
+ * @evidence contracts/common.md#clear-and-simple-design A thin wrapper over the shared comparison with the opposite outcome.
193
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The exception filter is the caller's; the function contains no key name of its own.
194
+ * @evidence contracts/common.md#meaningful-documentation The comment states that the rules are those of `equals`, and gives examples.
126
195
  */
127
196
  function notEquals<X, Y extends X = X>(title: string, x: X, y: Y | null | undefined, exception?: (key: string) => boolean): void;
128
197
  /**
@@ -132,29 +201,43 @@ export declare namespace TestValidator {
132
201
  * successfully without throwing an error or rejecting, this validator will
133
202
  * throw an exception. Supports both synchronous and asynchronous functions.
134
203
  *
204
+ * Processing cost: The task is invoked once and its settlement is classified
205
+ * with constant bookkeeping; no retry or repeated execution occurs.
206
+ *
207
+ * Reuse: Each invocation must evaluate its supplied task or request to
208
+ * observe current behavior; prior results cannot replace these effectful
209
+ * checks.
210
+ *
211
+ * Resource ownership: The returned promise retains invocation-local state
212
+ * until settlement. The callback owns its external resources, and this
213
+ * validator provides no cancellation or timeout.
214
+ *
135
215
  * @example
136
- * ```typescript
137
216
  * // Synchronous error validation
138
- * TestValidator.error("should reject invalid email",
139
- * () => validateEmail("invalid-email")
217
+ * TestValidator.error("should reject invalid email", () =>
218
+ * validateEmail("invalid-email"),
140
219
  * );
141
220
  *
142
221
  * // Asynchronous error validation
143
- * await TestValidator.error("should reject unauthorized access",
144
- * async () => await api.functional.getSecretData()
222
+ * await TestValidator.error(
223
+ * "should reject unauthorized access",
224
+ * async () => await api.functional.getSecretData(),
145
225
  * );
146
226
  *
147
227
  * // Validate input validation
148
- * TestValidator.error("should throw on empty string",
149
- * () => processRequiredInput("")
228
+ * TestValidator.error("should throw on empty string", () =>
229
+ * processRequiredInput(""),
150
230
  * );
151
- * ```;
152
231
  *
153
232
  * @param title - Descriptive title used in error messages when no error
154
233
  * occurs
155
234
  * @param task - The function that should throw an error or reject
156
235
  * @returns Void or Promise<void> based on the input type
157
236
  * @throws Error when the task function does not throw an error or reject
237
+ * @evidence contracts/common.md#principled-implementation The task is run inside a `try` so that only its own throw counts, a promise is awaited and a rejection counts as the expected error, and a task that neither throws nor rejects raises the failure outside the `try`, so the failure cannot be swallowed.
238
+ * @evidence contracts/common.md#clear-and-simple-design One function with a synchronous and an asynchronous path selected by the returned value.
239
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Any error satisfies it, as documented, and no error type is special-cased.
240
+ * @evidence contracts/common.md#meaningful-documentation The comment states that an exception is required, the return type rule, and the thrown error, with examples.
158
241
  */
159
242
  function error<T>(title: string, task: () => T): T extends Promise<any> ? Promise<void> : void;
160
243
  /**
@@ -164,23 +247,40 @@ export declare namespace TestValidator {
164
247
  * function throws an HttpError with one of the specified status codes. Useful
165
248
  * for testing API endpoints, authentication, and authorization logic.
166
249
  *
250
+ * Processing cost: The task is invoked once. Classification reads the thrown
251
+ * shape once and scans the expected status list until a match, using O(S)
252
+ * worst-case status comparisons and constant auxiliary state.
253
+ *
254
+ * Reuse: Each invocation must evaluate its supplied task or request to
255
+ * observe current behavior; prior results cannot replace these effectful
256
+ * checks.
257
+ *
258
+ * Resource ownership: The returned promise retains invocation-local state
259
+ * until settlement. The callback owns its external resources, and this
260
+ * validator provides no cancellation or timeout.
261
+ *
167
262
  * @example
168
- * ```typescript
169
263
  * // Validate 401 Unauthorized
170
- * await TestValidator.httpError("should return 401 for invalid token", 401,
171
- * async () => await api.functional.getProtectedResource("invalid-token")
264
+ * await TestValidator.httpError(
265
+ * "should return 401 for invalid token",
266
+ * 401,
267
+ * async () =>
268
+ * await api.functional.getProtectedResource("invalid-token"),
172
269
  * );
173
270
  *
174
271
  * // Validate multiple possible error codes
175
- * await TestValidator.httpError("should return client error", [400, 404, 422],
176
- * async () => await api.functional.updateNonexistentResource(data)
272
+ * await TestValidator.httpError(
273
+ * "should return client error",
274
+ * [400, 404, 422],
275
+ * async () => await api.functional.updateNonexistentResource(data),
177
276
  * );
178
277
  *
179
278
  * // Validate server errors
180
- * TestValidator.httpError("should handle server errors", [500, 502, 503],
181
- * () => callFaultyEndpoint()
279
+ * TestValidator.httpError(
280
+ * "should handle server errors",
281
+ * [500, 502, 503],
282
+ * () => callFaultyEndpoint(),
182
283
  * );
183
- * ```;
184
284
  *
185
285
  * @param title - Descriptive title used in error messages
186
286
  * @param status - Expected status code(s), can be a single number or array
@@ -188,6 +288,10 @@ export declare namespace TestValidator {
188
288
  * @returns Void or Promise<void> based on the input type
189
289
  * @throws Error when function doesn't throw HttpError or status code doesn't
190
290
  * match
291
+ * @evidence contracts/common.md#principled-implementation The thrown value must expose a constructor named `HttpError` and one expected numeric status, matched by name because generated SDKs define their own classes. Missing or throwing properties make classification fail instead of escaping the expectation. The returned promise chain propagates rejection-handler failures without leaving a separately bridged promise pending.
292
+ * @evidence contracts/common.md#clear-and-simple-design One predicate reads the thrown value once and is shared by the synchronous and asynchronous paths; asynchronous settlement uses the task's own promise chain.
293
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The check follows the documented error shape, not a specific SDK or status list.
294
+ * @evidence contracts/common.md#meaningful-documentation The comment documents the status argument, the two task kinds, and the thrown error, with examples.
191
295
  */
192
296
  function httpError<T>(title: string, status: number | number[], task: () => T): T extends Promise<any> ? Promise<void> : void;
193
297
  /**
@@ -202,22 +306,40 @@ export declare namespace TestValidator {
202
306
  * is compared. An empty result against expected entities, or the reverse,
203
307
  * fails.
204
308
  *
309
+ * Processing cost: Only the common prefix of P entities is sliced, converted
310
+ * to id strings and compared, giving O(P) entries and temporary storage;
311
+ * string conversion and comparison add their text costs.
312
+ *
205
313
  * @example
206
- * ```typescript
207
314
  * // Test article pagination
208
- * const expectedArticles = await db.articles.findAll({ order: 'created_at DESC' });
209
- * const actualArticles = await api.functional.getArticles({ page: 1, limit: 10 });
315
+ * const expectedArticles = await db.articles.findAll({
316
+ * order: "created_at DESC",
317
+ * });
318
+ * const actualArticles = await api.functional.getArticles({
319
+ * page: 1,
320
+ * limit: 10,
321
+ * });
210
322
  *
211
- * TestValidator.index("article pagination order", expectedArticles, actualArticles,
212
- * true // enable trace logging
323
+ * TestValidator.index(
324
+ * "article pagination order",
325
+ * expectedArticles,
326
+ * actualArticles,
327
+ * true, // enable trace logging
213
328
  * );
214
329
  *
215
330
  * // Test user search results
216
- * const manuallyFilteredUsers = allUsers.filter(u => u.name.includes("John"));
217
- * const apiSearchResults = await api.functional.searchUsers({ query: "John" });
331
+ * const manuallyFilteredUsers = allUsers.filter((u) =>
332
+ * u.name.includes("John"),
333
+ * );
334
+ * const apiSearchResults = await api.functional.searchUsers({
335
+ * query: "John",
336
+ * });
218
337
  *
219
- * TestValidator.index("user search results", manuallyFilteredUsers, apiSearchResults);
220
- * ```;
338
+ * TestValidator.index(
339
+ * "user search results",
340
+ * manuallyFilteredUsers,
341
+ * apiSearchResults,
342
+ * );
221
343
  *
222
344
  * @param title - Descriptive title used in error messages when order differs
223
345
  * @param expected - The expected entities in correct order
@@ -225,6 +347,10 @@ export declare namespace TestValidator {
225
347
  * @param trace - Optional flag to enable debug logging (default: false)
226
348
  * @throws Error when entity order differs between expected and actual results
227
349
  * over their common prefix, or when exactly one of them is empty
350
+ * @evidence contracts/common.md#principled-implementation A page holds the first entities of the expected list, so the two id lists are compared over their common prefix, and one side being empty while the other is not is a difference because there is no prefix to compare; ids are compared as strings.
351
+ * @evidence contracts/common.md#clear-and-simple-design One function over the id lists produced by a private helper, with an optional trace flag.
352
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Only ids are compared, with no entity type or field named in the function.
353
+ * @evidence contracts/common.md#meaningful-documentation The comment states the prefix rule, the empty rule, the trace flag, and the thrown error, with examples.
228
354
  */
229
355
  const index: <X extends IEntity<any>, Y extends X = X>(title: string, expected: X[], gotten: Y[], trace?: boolean) => void;
230
356
  /**
@@ -236,15 +362,27 @@ export declare namespace TestValidator {
236
362
  * API, and compares results. Validates that search APIs return the correct
237
363
  * subset of data matching the search criteria.
238
364
  *
365
+ * Processing cost: For K sampled entities from N entries, sparse sampling
366
+ * costs O(K), each reference filter scans N entries and each returned page
367
+ * prefix is compared once. Calls are sequential and one sample result is live
368
+ * at a time.
369
+ *
370
+ * Reuse: Each invocation must evaluate its supplied task or request to
371
+ * observe current behavior; prior results cannot replace these effectful
372
+ * checks.
373
+ *
374
+ * Resource ownership: The returned promise retains invocation-local state
375
+ * until settlement. The callback owns its external resources, and this
376
+ * validator provides no cancellation or timeout.
377
+ *
239
378
  * @example
240
- * ```typescript
241
379
  * // Test article search functionality with exact matching
242
380
  * const allArticles = await db.articles.findAll();
243
381
  * const searchValidator = TestValidator.search(
244
382
  * "article search API",
245
383
  * (req) => api.searchArticles(req),
246
384
  * allArticles,
247
- * 5 // test with 5 random samples
385
+ * 5, // test with 5 random samples
248
386
  * );
249
387
  *
250
388
  * // Test exact match search
@@ -252,7 +390,7 @@ export declare namespace TestValidator {
252
390
  * fields: ["title"],
253
391
  * values: (article) => [article.title], // full title for exact match
254
392
  * filter: (article, [title]) => article.title === title, // exact match
255
- * request: ([title]) => ({ search: { title } })
393
+ * request: ([title]) => ({ search: { title } }),
256
394
  * });
257
395
  *
258
396
  * // Test partial match search with includes
@@ -260,7 +398,7 @@ export declare namespace TestValidator {
260
398
  * fields: ["content"],
261
399
  * values: (article) => [article.content.substring(0, 20)], // partial content
262
400
  * filter: (article, [keyword]) => article.content.includes(keyword),
263
- * request: ([keyword]) => ({ q: keyword })
401
+ * request: ([keyword]) => ({ q: keyword }),
264
402
  * });
265
403
  *
266
404
  * // Test multi-field search with exact matching
@@ -269,9 +407,8 @@ export declare namespace TestValidator {
269
407
  * values: (article) => [article.writer, article.title],
270
408
  * filter: (article, [writer, title]) =>
271
409
  * article.writer === writer && article.title === title,
272
- * request: ([writer, title]) => ({ search: { writer, title } })
410
+ * request: ([writer, title]) => ({ search: { writer, title } }),
273
411
  * });
274
- * ```;
275
412
  *
276
413
  * @param title - Descriptive title used in error messages when search fails
277
414
  * @param getter - API function that performs the search
@@ -279,6 +416,10 @@ export declare namespace TestValidator {
279
416
  * @param sampleCount - Number of random samples to test (default: 1)
280
417
  * @returns A function that accepts search configuration properties
281
418
  * @throws Error when API search results don't match manual filtering results
419
+ * @evidence 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.
420
+ * @evidence 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`.
421
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The sample, values, filter, and request all come from the caller's configuration.
422
+ * @evidence contracts/common.md#meaningful-documentation The comment documents the steps, the parameters, and the thrown error, with examples.
282
423
  */
283
424
  const search: <Entity extends IEntity<any>, Request>(title: string, getter: (input: Request) => Promise<Entity[]>, total: Entity[], sampleCount?: number) => <Values extends any[]>(props: ISearchProps<Entity, Values, Request>) => Promise<void>;
284
425
  /**
@@ -292,6 +433,10 @@ export declare namespace TestValidator {
292
433
  * @template Values - Tuple type representing the search values extracted from
293
434
  * entities
294
435
  * @template Request - Type of the API request object
436
+ * @evidence contracts/common.md#principled-implementation The record supplies what the check needs from a test author: the field names for the message and the three functions that extract values, filter, and build the request.
437
+ * @evidence contracts/common.md#clear-and-simple-design A four-member record with the functions as methods.
438
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
439
+ * @evidence contracts/common.md#meaningful-documentation The comment names the role of the record and each member documents itself.
295
440
  */
296
441
  interface ISearchProps<Entity extends IEntity<any>, Values extends any[], Request> {
297
442
  /** Field names being searched, used in error messages for identification */
@@ -301,6 +446,10 @@ export declare namespace TestValidator {
301
446
  *
302
447
  * @param entity - The entity to extract search values from
303
448
  * @returns Tuple of values used for searching
449
+ * @evidence contracts/common.md#principled-implementation The search values are read from a sampled entity, so the search is exercised with values that occur in the dataset.
450
+ * @evidence contracts/common.md#clear-and-simple-design One method with one entity argument.
451
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It is caller code.
452
+ * @evidence contracts/common.md#meaningful-documentation The comment documents the parameter and the return value.
304
453
  */
305
454
  values(entity: Entity): Values;
306
455
  /**
@@ -309,6 +458,10 @@ export declare namespace TestValidator {
309
458
  * @param entity - Entity to test against criteria
310
459
  * @param values - Search values to match against
311
460
  * @returns True if entity matches the search criteria
461
+ * @evidence contracts/common.md#principled-implementation The predicate decides whether an entity matches the values, which is the manual reference against which the API is compared.
462
+ * @evidence contracts/common.md#clear-and-simple-design One predicate over an entity and the values.
463
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It is caller code.
464
+ * @evidence contracts/common.md#meaningful-documentation The comment documents the parameters and the return value.
312
465
  */
313
466
  filter(entity: Entity, values: Values): boolean;
314
467
  /**
@@ -316,6 +469,10 @@ export declare namespace TestValidator {
316
469
  *
317
470
  * @param values - Search values to include in request
318
471
  * @returns Request object for the search API
472
+ * @evidence contracts/common.md#principled-implementation The function builds the API request from the values, so the same values drive the manual filter and the call.
473
+ * @evidence contracts/common.md#clear-and-simple-design One method from values to the request.
474
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It is caller code.
475
+ * @evidence contracts/common.md#meaningful-documentation The comment documents the parameter and the return value.
319
476
  */
320
477
  request(values: Values): Request;
321
478
  }
@@ -327,15 +484,24 @@ export declare namespace TestValidator {
327
484
  * ascending/descending order, and optional filtering. Provides detailed error
328
485
  * reporting for sorting failures.
329
486
  *
487
+ * Processing cost: After one getter call, an optional filter scans N results
488
+ * and sortedness checks at most N minus one adjacent pairs. Signed field
489
+ * construction costs O(F); filter output costs O(N) space when requested.
490
+ *
491
+ * Reuse: Each invocation must evaluate its supplied task or request to
492
+ * observe current behavior; prior results cannot replace these effectful
493
+ * checks.
494
+ *
495
+ * Resource ownership: The returned promise retains invocation-local state
496
+ * until settlement. The callback owns its external resources, and this
497
+ * validator provides no cancellation or timeout.
498
+ *
330
499
  * @example
331
- * ```typescript
332
500
  * // Test single field sorting with GaffComparator
333
501
  * const sortValidator = TestValidator.sort(
334
502
  * "article sorting",
335
- * (sortable) => api.getArticles({ sort: sortable })
336
- * )("created_at")(
337
- * GaffComparator.dates((a) => a.created_at)
338
- * );
503
+ * (sortable) => api.getArticles({ sort: sortable }),
504
+ * )("created_at")(GaffComparator.dates((a) => a.created_at));
339
505
  *
340
506
  * await sortValidator("+"); // ascending
341
507
  * await sortValidator("-"); // descending
@@ -343,10 +509,10 @@ export declare namespace TestValidator {
343
509
  * // Test multi-field sorting with GaffComparator
344
510
  * const userSortValidator = TestValidator.sort(
345
511
  * "user sorting",
346
- * (sortable) => api.getUsers({ sort: sortable })
512
+ * (sortable) => api.getUsers({ sort: sortable }),
347
513
  * )("lastName", "firstName")(
348
514
  * GaffComparator.strings((user) => [user.lastName, user.firstName]),
349
- * (user) => user.isActive // only test active users
515
+ * (user) => user.isActive, // only test active users
350
516
  * );
351
517
  *
352
518
  * await userSortValidator("+", true); // ascending with trace logging
@@ -354,20 +520,24 @@ export declare namespace TestValidator {
354
520
  * // Custom comparator for complex logic
355
521
  * const customSortValidator = TestValidator.sort(
356
522
  * "custom sorting",
357
- * (sortable) => api.getProducts({ sort: sortable })
358
- * )("price", "rating")(
359
- * (a, b) => {
360
- * const priceDiff = a.price - b.price;
361
- * return priceDiff !== 0 ? priceDiff : b.rating - a.rating; // price asc, rating desc
362
- * }
363
- * );
364
- * ```;
523
+ * (sortable) => api.getProducts({ sort: sortable }),
524
+ * )(
525
+ * "price",
526
+ * "rating",
527
+ * )((a, b) => {
528
+ * const priceDiff = a.price - b.price;
529
+ * return priceDiff !== 0 ? priceDiff : b.rating - a.rating; // price asc, rating desc
530
+ * });
365
531
  *
366
532
  * @param title - Descriptive title used in error messages when sorting fails
367
533
  * @param getter - API function that fetches sorted data
368
534
  * @returns A currying function chain: field names, comparator, then direction
369
535
  * @throws Error when API results are not properly sorted according to
370
536
  * specification
537
+ * @evidence contracts/common.md#principled-implementation The API is called with the signed field names, its result is optionally filtered, and the comparator (reversed for the descending direction) is applied to adjacent pairs, so any adjacent pair out of order fails; checking adjacent pairs suffices for a total preorder.
538
+ * @evidence contracts/common.md#clear-and-simple-design The function is curried in three steps so the request, the comparator, and the direction can be given at the moments each is known.
539
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The order is judged by the caller's comparator, with no field or direction special-cased.
540
+ * @evidence contracts/common.md#meaningful-documentation The comment documents each stage, the parameters, and the thrown error, with examples.
371
541
  */
372
542
  const sort: <T extends object, Fields extends string, Sortable extends Array<`-${Fields}` | `+${Fields}`> = Array<`-${Fields}` | `+${Fields}`>>(title: string, getter: (sortable: Sortable) => Promise<T[]>) => (...fields: Fields[]) => (comp: (x: T, y: T) => number, filter?: (elem: T) => boolean) => (direction: "+" | "-", trace?: boolean) => Promise<void>;
373
543
  /**
@@ -377,14 +547,18 @@ export declare namespace TestValidator {
377
547
  * prefixed with '+' for ascending order or '-' for descending order.
378
548
  *
379
549
  * @example
380
- * ```typescript
381
- * type UserSortable = TestValidator.Sortable<"name" | "email" | "created_at">;
550
+ * type UserSortable = TestValidator.Sortable<
551
+ * "name" | "email" | "created_at"
552
+ * >;
382
553
  * // Results in: Array<"-name" | "+name" | "-email" | "+email" | "-created_at" | "+created_at">
383
554
  *
384
555
  * const userSort: UserSortable = ["+name", "-created_at"];
385
- * ```;
386
556
  *
387
557
  * @template Literal - String literal type representing available field names
558
+ * @evidence contracts/common.md#principled-implementation A sortable is an array of field names with a leading `+` or `-`, the notation the API under test receives.
559
+ * @evidence contracts/common.md#clear-and-simple-design A single template-literal type.
560
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
561
+ * @evidence contracts/common.md#meaningful-documentation The comment states the notation.
388
562
  */
389
563
  type Sortable<Literal extends string> = Array<`-${Literal}` | `+${Literal}`>;
390
564
  }