@nestia/e2e 11.0.0-dev.20260313 → 11.0.0-dev.20260313-2

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.
@@ -0,0 +1,389 @@
1
+ /**
2
+ * A comprehensive collection of E2E validation utilities for testing
3
+ * applications.
4
+ *
5
+ * TestValidator provides type-safe validation functions for common testing
6
+ * scenarios including condition checking, equality validation, error testing,
7
+ * HTTP error validation, pagination testing, search functionality validation,
8
+ * and sorting validation.
9
+ *
10
+ * Most functions use direct parameter passing for simplicity, while some
11
+ * maintain currying patterns for advanced composition. All provide detailed
12
+ * error messages for debugging failed assertions.
13
+ *
14
+ * @author Jeongho Nam - https://github.com/samchon
15
+ * @example
16
+ * ```typescript
17
+ * // Basic condition testing
18
+ * TestValidator.predicate("user should be authenticated", user.isAuthenticated);
19
+ *
20
+ * // Equality validation
21
+ * TestValidator.equals("API response should match expected", x, y);
22
+ *
23
+ * // Error validation
24
+ * TestValidator.error("should throw on invalid input", () => assertInput(""));
25
+ * ```;
26
+ */
27
+ export declare namespace TestValidator {
28
+ /**
29
+ * Validates that a given condition evaluates to true.
30
+ *
31
+ * Supports synchronous boolean values, synchronous functions returning
32
+ * boolean, and asynchronous functions returning Promise<boolean>. The return
33
+ * type is automatically inferred based on the input type.
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * // Synchronous boolean
38
+ * TestValidator.predicate("user should exist", user !== null);
39
+ *
40
+ * // Synchronous function
41
+ * TestValidator.predicate("array should be empty", () => arr.length === 0);
42
+ *
43
+ * // Asynchronous function
44
+ * await TestValidator.predicate("database should be connected",
45
+ * async () => await db.ping()
46
+ * );
47
+ * ```;
48
+ *
49
+ * @param title - Descriptive title used in error messages when validation
50
+ * fails
51
+ * @param condition - The condition to validate (boolean, function, or async
52
+ * function)
53
+ * @returns Void or Promise<void> based on the input type
54
+ * @throws Error with descriptive message when condition is not satisfied
55
+ */
56
+ function predicate<T extends boolean | (() => boolean) | (() => Promise<boolean>)>(title: string, condition: T): T extends () => Promise<boolean> ? Promise<void> : void;
57
+ /**
58
+ * Validates deep equality between two values using JSON comparison.
59
+ *
60
+ * Performs recursive comparison of objects and arrays. Supports an optional
61
+ * exception filter to ignore specific keys during comparison. Useful for
62
+ * validating API responses, data transformations, and object state changes.
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * // Basic equality
67
+ * TestValidator.equals("response should match expected", expectedUser, actualUser);
68
+ *
69
+ * // Ignore timestamps in comparison
70
+ * TestValidator.equals("user data should match", expectedUser, actualUser,
71
+ * (key) => key === "updatedAt"
72
+ * );
73
+ *
74
+ * // Validate API response structure
75
+ * TestValidator.equals("API response structure",
76
+ * { id: 1, name: "John" },
77
+ * { id: 1, name: "John" }
78
+ * );
79
+ *
80
+ * // Type-safe nullable comparisons
81
+ * const nullableData: { name: string } | null = getData();
82
+ * TestValidator.equals("nullable check", nullableData, null);
83
+ * ```;
84
+ *
85
+ * @param title - Descriptive title used in error messages when values differ
86
+ * @param X - The first value to compare
87
+ * @param y - The second value to compare (can be null or undefined)
88
+ * @param exception - Optional filter function to exclude specific keys from
89
+ * comparison
90
+ * @throws Error with detailed diff information when values are not equal
91
+ */
92
+ function equals<X, Y extends X = X>(title: string, X: X, y: Y | null | undefined, exception?: (key: string) => boolean): void;
93
+ /**
94
+ * Validates deep inequality between two values using JSON comparison.
95
+ *
96
+ * 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
99
+ * different, or mutations have occurred.
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * // Basic inequality
104
+ * TestValidator.notEquals("user should be different after update", originalUser, updatedUser);
105
+ *
106
+ * // Ignore timestamps in comparison
107
+ * TestValidator.notEquals("user data should differ", originalUser, modifiedUser,
108
+ * (key) => key === "updatedAt"
109
+ * );
110
+ *
111
+ * // Validate state changes
112
+ * TestValidator.notEquals("state should have changed", initialState, currentState);
113
+ *
114
+ * // Type-safe nullable comparisons
115
+ * const mutableData: { count: number } | null = getMutableData();
116
+ * TestValidator.notEquals("should have changed", mutableData, null);
117
+ * ```;
118
+ *
119
+ * @param title - Descriptive title used in error messages when values are
120
+ * equal
121
+ * @param x - The first value to compare
122
+ * @param y - The second value to compare (can be null or undefined)
123
+ * @param exception - Optional filter function to exclude specific keys from
124
+ * comparison
125
+ * @throws Error when values are equal (indicating validation failure)
126
+ */
127
+ function notEquals<X, Y extends X = X>(title: string, x: X, y: Y | null | undefined, exception?: (key: string) => boolean): void;
128
+ /**
129
+ * Validates that a function throws an error or rejects when executed.
130
+ *
131
+ * Expects the provided function to fail. If the function executes
132
+ * successfully without throwing an error or rejecting, this validator will
133
+ * throw an exception. Supports both synchronous and asynchronous functions.
134
+ *
135
+ * @example
136
+ * ```typescript
137
+ * // Synchronous error validation
138
+ * TestValidator.error("should reject invalid email",
139
+ * () => validateEmail("invalid-email")
140
+ * );
141
+ *
142
+ * // Asynchronous error validation
143
+ * await TestValidator.error("should reject unauthorized access",
144
+ * async () => await api.functional.getSecretData()
145
+ * );
146
+ *
147
+ * // Validate input validation
148
+ * TestValidator.error("should throw on empty string",
149
+ * () => processRequiredInput("")
150
+ * );
151
+ * ```;
152
+ *
153
+ * @param title - Descriptive title used in error messages when no error
154
+ * occurs
155
+ * @param task - The function that should throw an error or reject
156
+ * @returns Void or Promise<void> based on the input type
157
+ * @throws Error when the task function does not throw an error or reject
158
+ */
159
+ function error<T>(title: string, task: () => T): T extends Promise<any> ? Promise<void> : void;
160
+ /**
161
+ * Validates that a function throws an HTTP error with specific status codes.
162
+ *
163
+ * Specialized error validator for HTTP operations. Validates that the
164
+ * function throws an HttpError with one of the specified status codes. Useful
165
+ * for testing API endpoints, authentication, and authorization logic.
166
+ *
167
+ * @example
168
+ * ```typescript
169
+ * // Validate 401 Unauthorized
170
+ * await TestValidator.httpError("should return 401 for invalid token", 401,
171
+ * async () => await api.functional.getProtectedResource("invalid-token")
172
+ * );
173
+ *
174
+ * // Validate multiple possible error codes
175
+ * await TestValidator.httpError("should return client error", [400, 404, 422],
176
+ * async () => await api.functional.updateNonexistentResource(data)
177
+ * );
178
+ *
179
+ * // Validate server errors
180
+ * TestValidator.httpError("should handle server errors", [500, 502, 503],
181
+ * () => callFaultyEndpoint()
182
+ * );
183
+ * ```;
184
+ *
185
+ * @param title - Descriptive title used in error messages
186
+ * @param status - Expected status code(s), can be a single number or array
187
+ * @param task - The function that should throw an HttpError
188
+ * @returns Void or Promise<void> based on the input type
189
+ * @throws Error when function doesn't throw HttpError or status code doesn't
190
+ * match
191
+ */
192
+ function httpError<T>(title: string, status: number | number[], task: () => T): T extends Promise<any> ? Promise<void> : void;
193
+ /**
194
+ * Validates pagination index API results against expected entity order.
195
+ *
196
+ * Compares the order of entities returned by a pagination API with manually
197
+ * sorted expected results. Validates that entity IDs appear in the correct
198
+ * sequence. Commonly used for testing database queries, search results, and
199
+ * any paginated data APIs.
200
+ *
201
+ * @example
202
+ * ```typescript
203
+ * // Test article pagination
204
+ * const expectedArticles = await db.articles.findAll({ order: 'created_at DESC' });
205
+ * const actualArticles = await api.functional.getArticles({ page: 1, limit: 10 });
206
+ *
207
+ * TestValidator.index("article pagination order", expectedArticles, actualArticles,
208
+ * true // enable trace logging
209
+ * );
210
+ *
211
+ * // Test user search results
212
+ * const manuallyFilteredUsers = allUsers.filter(u => u.name.includes("John"));
213
+ * const apiSearchResults = await api.functional.searchUsers({ query: "John" });
214
+ *
215
+ * TestValidator.index("user search results", manuallyFilteredUsers, apiSearchResults);
216
+ * ```;
217
+ *
218
+ * @param title - Descriptive title used in error messages when order differs
219
+ * @param expected - The expected entities in correct order
220
+ * @param gotten - The actual entities returned by the API
221
+ * @param trace - Optional flag to enable debug logging (default: false)
222
+ * @throws Error when entity order differs between expected and actual results
223
+ */
224
+ const index: <X extends IEntity<any>, Y extends X = X>(title: string, expected: X[], gotten: Y[], trace?: boolean) => void;
225
+ /**
226
+ * Validates search functionality by testing API results against manual
227
+ * filtering.
228
+ *
229
+ * Comprehensive search validation that samples entities from a complete
230
+ * dataset, extracts search values, applies manual filtering, calls the search
231
+ * API, and compares results. Validates that search APIs return the correct
232
+ * subset of data matching the search criteria.
233
+ *
234
+ * @example
235
+ * ```typescript
236
+ * // Test article search functionality with exact matching
237
+ * const allArticles = await db.articles.findAll();
238
+ * const searchValidator = TestValidator.search(
239
+ * "article search API",
240
+ * (req) => api.searchArticles(req),
241
+ * allArticles,
242
+ * 5 // test with 5 random samples
243
+ * );
244
+ *
245
+ * // Test exact match search
246
+ * await searchValidator({
247
+ * fields: ["title"],
248
+ * values: (article) => [article.title], // full title for exact match
249
+ * filter: (article, [title]) => article.title === title, // exact match
250
+ * request: ([title]) => ({ search: { title } })
251
+ * });
252
+ *
253
+ * // Test partial match search with includes
254
+ * await searchValidator({
255
+ * fields: ["content"],
256
+ * values: (article) => [article.content.substring(0, 20)], // partial content
257
+ * filter: (article, [keyword]) => article.content.includes(keyword),
258
+ * request: ([keyword]) => ({ q: keyword })
259
+ * });
260
+ *
261
+ * // Test multi-field search with exact matching
262
+ * await searchValidator({
263
+ * fields: ["writer", "title"],
264
+ * values: (article) => [article.writer, article.title],
265
+ * filter: (article, [writer, title]) =>
266
+ * article.writer === writer && article.title === title,
267
+ * request: ([writer, title]) => ({ search: { writer, title } })
268
+ * });
269
+ * ```;
270
+ *
271
+ * @param title - Descriptive title used in error messages when search fails
272
+ * @param getter - API function that performs the search
273
+ * @param total - Complete dataset to sample from for testing
274
+ * @param sampleCount - Number of random samples to test (default: 1)
275
+ * @returns A function that accepts search configuration properties
276
+ * @throws Error when API search results don't match manual filtering results
277
+ */
278
+ 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>;
279
+ /**
280
+ * Configuration interface for search validation functionality.
281
+ *
282
+ * Defines the structure needed to validate search operations by specifying
283
+ * how to extract search values from entities, filter the dataset manually,
284
+ * and construct API requests.
285
+ *
286
+ * @template Entity - Type of entities being searched, must have an ID field
287
+ * @template Values - Tuple type representing the search values extracted from
288
+ * entities
289
+ * @template Request - Type of the API request object
290
+ */
291
+ interface ISearchProps<Entity extends IEntity<any>, Values extends any[], Request> {
292
+ /** Field names being searched, used in error messages for identification */
293
+ fields: string[];
294
+ /**
295
+ * Extracts search values from a sample entity
296
+ *
297
+ * @param entity - The entity to extract search values from
298
+ * @returns Tuple of values used for searching
299
+ */
300
+ values(entity: Entity): Values;
301
+ /**
302
+ * Manual filter function to determine if an entity matches search criteria
303
+ *
304
+ * @param entity - Entity to test against criteria
305
+ * @param values - Search values to match against
306
+ * @returns True if entity matches the search criteria
307
+ */
308
+ filter(entity: Entity, values: Values): boolean;
309
+ /**
310
+ * Constructs API request object from search values
311
+ *
312
+ * @param values - Search values to include in request
313
+ * @returns Request object for the search API
314
+ */
315
+ request(values: Values): Request;
316
+ }
317
+ /**
318
+ * Validates sorting functionality of pagination APIs.
319
+ *
320
+ * Tests sorting operations by calling the API with sort parameters and
321
+ * validating that results are correctly ordered. Supports multiple fields,
322
+ * ascending/descending order, and optional filtering. Provides detailed error
323
+ * reporting for sorting failures.
324
+ *
325
+ * @example
326
+ * ```typescript
327
+ * // Test single field sorting with GaffComparator
328
+ * const sortValidator = TestValidator.sort(
329
+ * "article sorting",
330
+ * (sortable) => api.getArticles({ sort: sortable })
331
+ * )("created_at")(
332
+ * GaffComparator.dates((a) => a.created_at)
333
+ * );
334
+ *
335
+ * await sortValidator("+"); // ascending
336
+ * await sortValidator("-"); // descending
337
+ *
338
+ * // Test multi-field sorting with GaffComparator
339
+ * const userSortValidator = TestValidator.sort(
340
+ * "user sorting",
341
+ * (sortable) => api.getUsers({ sort: sortable })
342
+ * )("lastName", "firstName")(
343
+ * GaffComparator.strings((user) => [user.lastName, user.firstName]),
344
+ * (user) => user.isActive // only test active users
345
+ * );
346
+ *
347
+ * await userSortValidator("+", true); // ascending with trace logging
348
+ *
349
+ * // Custom comparator for complex logic
350
+ * const customSortValidator = TestValidator.sort(
351
+ * "custom sorting",
352
+ * (sortable) => api.getProducts({ sort: sortable })
353
+ * )("price", "rating")(
354
+ * (a, b) => {
355
+ * const priceDiff = a.price - b.price;
356
+ * return priceDiff !== 0 ? priceDiff : b.rating - a.rating; // price asc, rating desc
357
+ * }
358
+ * );
359
+ * ```;
360
+ *
361
+ * @param title - Descriptive title used in error messages when sorting fails
362
+ * @param getter - API function that fetches sorted data
363
+ * @returns A currying function chain: field names, comparator, then direction
364
+ * @throws Error when API results are not properly sorted according to
365
+ * specification
366
+ */
367
+ 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>;
368
+ /**
369
+ * Type alias for sortable field specifications.
370
+ *
371
+ * Represents an array of sort field specifications where each field can be
372
+ * prefixed with '+' for ascending order or '-' for descending order.
373
+ *
374
+ * @example
375
+ * ```typescript
376
+ * type UserSortable = TestValidator.Sortable<"name" | "email" | "created_at">;
377
+ * // Results in: Array<"-name" | "+name" | "-email" | "+email" | "-created_at" | "+created_at">
378
+ *
379
+ * const userSort: UserSortable = ["+name", "-created_at"];
380
+ * ```;
381
+ *
382
+ * @template Literal - String literal type representing available field names
383
+ */
384
+ type Sortable<Literal extends string> = Array<`-${Literal}` | `+${Literal}`>;
385
+ }
386
+ interface IEntity<Type extends string | number | bigint> {
387
+ id: Type;
388
+ }
389
+ export {};