@jterrazz/test 10.1.0 → 11.0.0
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.
- package/README.md +33 -19
- package/dist/appium.adapter.js +23 -10
- package/dist/checker.js +0 -1
- package/dist/index.d.ts +214 -153
- package/dist/index.js +206 -665
- package/dist/intercept.js +37 -84
- package/dist/match.js +12 -1
- package/dist/oxlint.cjs +316 -56
- package/dist/oxlint.js +316 -56
- package/dist/queue.js +555 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -10,12 +10,14 @@ import { DeepMockProxy } from "vitest-mock-extended";
|
|
|
10
10
|
* (`expected/*.txt`). One grammar, one vocabulary (CONVENTIONS D4).
|
|
11
11
|
*/
|
|
12
12
|
/** The frozen token vocabulary (CONVENTIONS D4) plus the code-only kinds. */
|
|
13
|
-
type MatcherKind = 'any' | 'base64' | 'date' | 'duration' | 'email' | 'float' | 'hex' | 'int' | 'ip' | 'iso8601' | 'number' | 'path' | 'port' | 'ref' | 'regex' | 'semver' | 'sha' | 'string' | 'time' | 'ulid' | 'url' | 'uuid' | 'workdir';
|
|
13
|
+
type MatcherKind = 'any' | 'base64' | 'date' | 'duration' | 'email' | 'float' | 'hex' | 'includes' | 'int' | 'ip' | 'iso8601' | 'number' | 'path' | 'port' | 'ref' | 'regex' | 'semver' | 'sha' | 'string' | 'time' | 'ulid' | 'url' | 'uuid' | 'workdir';
|
|
14
14
|
/**
|
|
15
15
|
* A dynamic-value matcher. Created via the {@link match} factories — never
|
|
16
16
|
* constructed directly by user code.
|
|
17
17
|
*/
|
|
18
18
|
declare class Matcher {
|
|
19
|
+
/** For kind 'includes': the substring the actual value must contain. */
|
|
20
|
+
readonly includes?: string;
|
|
19
21
|
readonly kind: MatcherKind;
|
|
20
22
|
/** For kind 'ref': the capture to assert inequality against. */
|
|
21
23
|
readonly notRef?: string;
|
|
@@ -24,6 +26,7 @@ declare class Matcher {
|
|
|
24
26
|
/** For kind 'regex': the pattern the actual value must match. */
|
|
25
27
|
readonly regex?: RegExp;
|
|
26
28
|
constructor(kind: MatcherKind, options?: {
|
|
29
|
+
includes?: string;
|
|
27
30
|
notRef?: string;
|
|
28
31
|
refName?: string;
|
|
29
32
|
regex?: RegExp;
|
|
@@ -61,6 +64,13 @@ declare const match: {
|
|
|
61
64
|
float: () => Matcher;
|
|
62
65
|
/** Matches a hexadecimal string. */
|
|
63
66
|
hex: () => Matcher;
|
|
67
|
+
/**
|
|
68
|
+
* Matches a string CONTAINING the given substring. Code-only, like
|
|
69
|
+
* {@link match.regex} — the `{{token}}` fixture vocabulary does not grow.
|
|
70
|
+
* The explicit escape hatch now that contract string filters
|
|
71
|
+
* (`openai.chat({ user })`) mean exact equality.
|
|
72
|
+
*/
|
|
73
|
+
includes: (substring: string) => Matcher;
|
|
64
74
|
/** Matches an integer (or an integer string in text contexts). */
|
|
65
75
|
int: () => Matcher;
|
|
66
76
|
/** Matches an IPv4 address. */
|
|
@@ -389,43 +399,48 @@ interface CliPort {
|
|
|
389
399
|
//#endregion
|
|
390
400
|
//#region src/core/contracts/types.d.ts
|
|
391
401
|
/**
|
|
392
|
-
* The observed outgoing request, reduced to what
|
|
393
|
-
* Built once per request by the MSW
|
|
394
|
-
* {@link
|
|
402
|
+
* The observed outgoing request, reduced to what contract matchers inspect.
|
|
403
|
+
* Built once per request by the engine (MSW on api/jobs, the stub backend on
|
|
404
|
+
* website/mobile) and handed to {@link ContractRequest.match} and to a
|
|
405
|
+
* {@link ContractResponder}.
|
|
395
406
|
*/
|
|
396
407
|
interface MatchableRequest {
|
|
397
408
|
/** Parsed JSON body when the payload is JSON, the raw text otherwise, or `null` when absent. */
|
|
398
409
|
body: unknown;
|
|
399
410
|
/** Request headers, keyed by lowercased header name. */
|
|
400
411
|
headers: Record<string, string>;
|
|
401
|
-
/**
|
|
412
|
+
/** Uppercased HTTP method of the observed request. */
|
|
413
|
+
method: string;
|
|
414
|
+
/** The request URL — fully-qualified, or origin-relative for the stub backend. */
|
|
402
415
|
url: string;
|
|
403
416
|
}
|
|
404
417
|
/**
|
|
405
|
-
*
|
|
418
|
+
* The request half of a contract: which outgoing call it speaks for.
|
|
419
|
+
*
|
|
420
|
+
* `url` is either an absolute URL (string or RegExp), or a PATH FORM starting
|
|
421
|
+
* with `/` (`/articles/{{uuid}}`) which matches any origin — the shape a
|
|
422
|
+
* website/mobile app's own backend calls take. `{{token}}` segments compare
|
|
423
|
+
* structurally, declared query params are a subset of the observed ones.
|
|
406
424
|
*/
|
|
407
|
-
interface
|
|
408
|
-
/** Adapter name
|
|
425
|
+
interface ContractRequest {
|
|
426
|
+
/** Adapter name — `http` | `openai` | `anthropic`. */
|
|
409
427
|
adapter: string;
|
|
410
|
-
/** HTTP method to match. */
|
|
428
|
+
/** HTTP method to match. `*` matches any method. */
|
|
411
429
|
method: string;
|
|
412
|
-
/** URL
|
|
430
|
+
/** Absolute URL (string | RegExp) or an any-origin path form (`/articles/{{uuid}}`). */
|
|
413
431
|
url: RegExp | string;
|
|
414
|
-
/** Optional request matcher
|
|
432
|
+
/** Optional request matcher — the contract only fires if this returns true. */
|
|
415
433
|
match?: (request: MatchableRequest) => boolean;
|
|
416
|
-
/**
|
|
417
|
-
|
|
418
|
-
* Called when .intercept(trigger, 'adapter/file.json') loads a file.
|
|
419
|
-
*/
|
|
420
|
-
wrap: (data: unknown) => InterceptResponse;
|
|
434
|
+
/** Transform raw data into a provider-specific response envelope. */
|
|
435
|
+
wrap: (data: unknown) => ContractResponse;
|
|
421
436
|
}
|
|
422
437
|
/**
|
|
423
|
-
*
|
|
438
|
+
* The response half of a contract: what to reply when the request matches.
|
|
424
439
|
*/
|
|
425
|
-
interface
|
|
440
|
+
interface ContractResponse {
|
|
426
441
|
/** HTTP status code (default: 200). */
|
|
427
442
|
status?: number;
|
|
428
|
-
/** Response body
|
|
443
|
+
/** Response body — an object is JSON, a string is text, `null`/`undefined` is empty. */
|
|
429
444
|
body: unknown;
|
|
430
445
|
/** Response headers. */
|
|
431
446
|
headers?: Record<string, string>;
|
|
@@ -434,67 +449,101 @@ interface InterceptResponse {
|
|
|
434
449
|
}
|
|
435
450
|
/**
|
|
436
451
|
* A dynamic response: computed from the observed request at the moment the
|
|
437
|
-
*
|
|
438
|
-
* {@link MatchableRequest} the
|
|
439
|
-
* derive from the
|
|
452
|
+
* contract is served, rather than fixed ahead of time. Handed the same
|
|
453
|
+
* {@link MatchableRequest} the request half matched on, so the reply can echo
|
|
454
|
+
* or derive from the body/headers/url.
|
|
440
455
|
*/
|
|
441
|
-
type
|
|
456
|
+
type ContractResponder = (request: MatchableRequest) => ContractResponse;
|
|
442
457
|
/**
|
|
443
|
-
* What
|
|
444
|
-
*
|
|
458
|
+
* What a contract replies with: either a fixed {@link ContractResponse} or a
|
|
459
|
+
* {@link ContractResponder} evaluated per served request.
|
|
445
460
|
*/
|
|
446
|
-
type
|
|
447
|
-
/**
|
|
448
|
-
* A fully resolved intercept entry ready to be registered with MSW.
|
|
449
|
-
*/
|
|
450
|
-
interface InterceptEntry {
|
|
451
|
-
trigger: InterceptTrigger;
|
|
452
|
-
response: InterceptResponseValue;
|
|
453
|
-
}
|
|
461
|
+
type ContractResponseValue = ContractResponder | ContractResponse;
|
|
454
462
|
//#endregion
|
|
455
463
|
//#region src/core/contracts/contract.d.ts
|
|
456
464
|
/**
|
|
457
|
-
* A declared external interaction: what to match and what to reply
|
|
458
|
-
* in one named artifact. Contracts live in
|
|
459
|
-
* `contracts/` next to the tests that use them
|
|
460
|
-
*
|
|
461
|
-
*
|
|
462
|
-
* HTTP call stays mocked underneath (MSW).
|
|
465
|
+
* A declared external interaction: what to match (`request`) and what to reply
|
|
466
|
+
* (`response`), together in one named artifact. Contracts live in TypeScript
|
|
467
|
+
* files under `contracts/` next to the tests that use them, so the business
|
|
468
|
+
* payload (prompts, JSON responses) is visible at a glance while the real HTTP
|
|
469
|
+
* call stays mocked underneath.
|
|
463
470
|
*/
|
|
464
|
-
interface
|
|
465
|
-
|
|
471
|
+
interface Contract {
|
|
472
|
+
/** Which outgoing call this contract speaks for. */
|
|
473
|
+
request: ContractRequest;
|
|
466
474
|
/**
|
|
467
|
-
* The reply — a fixed {@link
|
|
468
|
-
* `(request) =>
|
|
475
|
+
* The reply — a fixed {@link ContractResponse}, or a function
|
|
476
|
+
* `(request) => ContractResponse` evaluated per served request when the
|
|
469
477
|
* response must derive from the incoming payload.
|
|
470
478
|
*/
|
|
471
|
-
response:
|
|
479
|
+
response: ContractResponseValue;
|
|
480
|
+
/**
|
|
481
|
+
* How many times this contract may serve. Omitted = unlimited (a
|
|
482
|
+
* re-render or a retry replays it). `n` = exhausted after n serves, so an
|
|
483
|
+
* ordered sequence is a finite contract followed by an unlimited tail.
|
|
484
|
+
*/
|
|
485
|
+
times?: number;
|
|
486
|
+
/**
|
|
487
|
+
* When true, the chain FAILS unless the contract was actually requested:
|
|
488
|
+
* at least once, or exactly `times` times when `times` is set. Turns a
|
|
489
|
+
* silently-unused declaration into a spec failure.
|
|
490
|
+
*/
|
|
491
|
+
required?: boolean;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* A composite of contracts — the unit tests import. Flat, ordered, immutable;
|
|
495
|
+
* `.with()` derives a variant without touching the original.
|
|
496
|
+
*/
|
|
497
|
+
interface Contracts {
|
|
498
|
+
/** The flattened contracts, in selection order. */
|
|
499
|
+
readonly contracts: readonly Contract[];
|
|
500
|
+
/**
|
|
501
|
+
* Derive a new composite: every base contract sharing a route with an
|
|
502
|
+
* override is REPLACED, and the overrides are PREPENDED — so a
|
|
503
|
+
* more-specific override wins first-match selection over a generic base
|
|
504
|
+
* route it does not replace.
|
|
505
|
+
*/
|
|
506
|
+
with: (...overrides: (Contract | Contract[] | Contracts)[]) => Contracts;
|
|
472
507
|
}
|
|
508
|
+
/** Any accepted contract input: one, a list, or a composite. */
|
|
509
|
+
type ContractInput = Contract | Contract[] | Contracts;
|
|
473
510
|
/**
|
|
474
|
-
* Declare
|
|
475
|
-
*
|
|
511
|
+
* Declare one contract. Identity function — its value is the enforced shape
|
|
512
|
+
* and the naming convention:
|
|
476
513
|
*
|
|
477
514
|
* @example
|
|
478
|
-
* // specs/api/reports/contracts/classify-article.
|
|
515
|
+
* // specs/api/reports/contracts/openai/classify-article.ts
|
|
479
516
|
* import { defineContract, openai } from '@jterrazz/test';
|
|
480
517
|
*
|
|
481
518
|
* export default defineContract({
|
|
482
|
-
*
|
|
519
|
+
* request: openai.responses({ user: PROMPT, tools: ['classify'] }),
|
|
483
520
|
* response: openai.reply({ categories: ['TECH'] }),
|
|
484
521
|
* });
|
|
485
522
|
*
|
|
486
523
|
* // Dynamic — the response is computed from the observed request:
|
|
487
524
|
* export default defineContract({
|
|
488
|
-
*
|
|
525
|
+
* request: http.post('https://api.example.com/echo'),
|
|
489
526
|
* response: (request) => http.json({ received: request.body }),
|
|
490
527
|
* });
|
|
528
|
+
*/
|
|
529
|
+
declare function defineContract(contract: Contract): Contract;
|
|
530
|
+
/**
|
|
531
|
+
* Compose contracts into the artifact a test imports — it's contracts all the
|
|
532
|
+
* way down: a composite may extend contracts, lists, and other composites,
|
|
533
|
+
* recursively, order preserved.
|
|
491
534
|
*
|
|
492
|
-
*
|
|
493
|
-
*
|
|
535
|
+
* `.with(...)` derives a scenario: contracts whose route the overrides claim
|
|
536
|
+
* are removed from the base, and the overrides are prepended. Under
|
|
537
|
+
* first-match selection a more specific override (`/articles/gone-1`) also
|
|
538
|
+
* wins over a generic base route (`/articles/{{uuid}}`) it does not replace.
|
|
494
539
|
*
|
|
495
|
-
*
|
|
540
|
+
* @example
|
|
541
|
+
* // contracts/newsroom.contracts.ts
|
|
542
|
+
* export default defineContracts(events, articleById);
|
|
543
|
+
* export const withArticleGone = (id: string) =>
|
|
544
|
+
* newsroom.with(articleGone(id));
|
|
496
545
|
*/
|
|
497
|
-
declare function
|
|
546
|
+
declare function defineContracts(...items: ContractInput[]): Contracts;
|
|
498
547
|
//#endregion
|
|
499
548
|
//#region src/core/ports/browser.port.d.ts
|
|
500
549
|
/**
|
|
@@ -975,30 +1024,6 @@ declare class PageResult extends BaseResult {
|
|
|
975
1024
|
get url(): string;
|
|
976
1025
|
}
|
|
977
1026
|
//#endregion
|
|
978
|
-
//#region src/core/http-files/intercept-file.d.ts
|
|
979
|
-
/** The declared request half of an exchange — the matching trigger. */
|
|
980
|
-
interface ExchangeRequest {
|
|
981
|
-
/** Declared header subset — names case-insensitive, values may carry `{{token}}`s. */
|
|
982
|
-
headers: Record<string, string>;
|
|
983
|
-
method: string;
|
|
984
|
-
/** Path as written, query string included (`/articles?event_id=…`). */
|
|
985
|
-
path: string;
|
|
986
|
-
}
|
|
987
|
-
/** The declared response half of an exchange — the stubbed reply. */
|
|
988
|
-
interface ExchangeResponse {
|
|
989
|
-
/** Parsed JSON body — or the raw text when the body is not valid JSON. */
|
|
990
|
-
body: unknown;
|
|
991
|
-
/** True when a body section is present. */
|
|
992
|
-
hasBody: boolean;
|
|
993
|
-
headers: Record<string, string>;
|
|
994
|
-
status: number;
|
|
995
|
-
}
|
|
996
|
-
/** One declared request/response pair of an `intercepts/*.http` file. */
|
|
997
|
-
interface InterceptExchange {
|
|
998
|
-
request: ExchangeRequest;
|
|
999
|
-
response: ExchangeResponse;
|
|
1000
|
-
}
|
|
1001
|
-
//#endregion
|
|
1002
1027
|
//#region src/core/specification/shared/stub-backend.d.ts
|
|
1003
1028
|
/** Options for the stub backend server. */
|
|
1004
1029
|
interface StubBackendOptions {
|
|
@@ -1009,11 +1034,10 @@ interface StubBackendOptions {
|
|
|
1009
1034
|
port?: number;
|
|
1010
1035
|
}
|
|
1011
1036
|
declare class StubBackend {
|
|
1012
|
-
|
|
1013
|
-
private entries;
|
|
1014
|
-
/** Guarded once the current chain declared at least one intercept. */
|
|
1037
|
+
/** Guarded once the current chain declared at least one contract. */
|
|
1015
1038
|
private guarded;
|
|
1016
1039
|
private readonly options;
|
|
1040
|
+
private queue;
|
|
1017
1041
|
private server;
|
|
1018
1042
|
private readonly unmatchedRequests;
|
|
1019
1043
|
private url;
|
|
@@ -1023,28 +1047,23 @@ declare class StubBackend {
|
|
|
1023
1047
|
/** Stop the server (idempotent). */
|
|
1024
1048
|
stop(): Promise<void>;
|
|
1025
1049
|
/**
|
|
1026
|
-
* Arm the stub for one chain: the declared
|
|
1027
|
-
* chain's wholesale,
|
|
1050
|
+
* Arm the stub for one chain: the declared contracts replace the previous
|
|
1051
|
+
* chain's wholesale, the queue restarts, and the unmatched log clears —
|
|
1028
1052
|
* the reset-between-chains databases already follow.
|
|
1029
1053
|
*/
|
|
1030
|
-
beginChain(
|
|
1054
|
+
beginChain(contracts: readonly Contract[]): void;
|
|
1031
1055
|
/**
|
|
1032
|
-
* The strict failure for the chain, or null
|
|
1033
|
-
* declared at least one
|
|
1034
|
-
*
|
|
1035
|
-
*
|
|
1056
|
+
* The strict failure for the chain, or null. Non-null when the chain
|
|
1057
|
+
* declared at least one contract AND either an unmatched request was
|
|
1058
|
+
* recorded, or a `required` contract was never satisfied. Enumerates every
|
|
1059
|
+
* unmatched request (method, path, count) plus the declared routes, so the
|
|
1060
|
+
* missing contract writes itself.
|
|
1036
1061
|
*/
|
|
1037
1062
|
violation(): Error | null;
|
|
1038
1063
|
private corsHeaders;
|
|
1039
1064
|
private describeRoutes;
|
|
1040
1065
|
private handle;
|
|
1041
1066
|
private record;
|
|
1042
|
-
/**
|
|
1043
|
-
* FIFO with a sticky tail: the first unconsumed matching exchange is
|
|
1044
|
-
* consumed; when every matching exchange is spent, the LAST one keeps
|
|
1045
|
-
* replying.
|
|
1046
|
-
*/
|
|
1047
|
-
private take;
|
|
1048
1067
|
}
|
|
1049
1068
|
//#endregion
|
|
1050
1069
|
//#region src/core/specification/shared/builder.d.ts
|
|
@@ -1068,7 +1087,7 @@ interface DockerSpecConfig {
|
|
|
1068
1087
|
interface SpecificationConfig {
|
|
1069
1088
|
/**
|
|
1070
1089
|
* The declared stub backend (website/mobile facets) — armed with the
|
|
1071
|
-
* chain's
|
|
1090
|
+
* chain's contracts before every terminal action.
|
|
1072
1091
|
*/
|
|
1073
1092
|
backend?: StubBackend;
|
|
1074
1093
|
/**
|
|
@@ -1136,6 +1155,11 @@ interface SpecificationConfig {
|
|
|
1136
1155
|
*/
|
|
1137
1156
|
transform?: (text: string) => string;
|
|
1138
1157
|
}
|
|
1158
|
+
/**
|
|
1159
|
+
* The `.intercept()` overload set, identical on every facet: one contract, a
|
|
1160
|
+
* list, a composite — or the inline `(request, response)` pair for a one-off.
|
|
1161
|
+
*/
|
|
1162
|
+
type InterceptMethod<T> = ((contracts: ContractInput) => T) & ((request: ContractRequest, response: ContractResponder | ContractResponse) => T);
|
|
1139
1163
|
/**
|
|
1140
1164
|
* The `api` facet — HTTP chain entry handed out by `specification.api()`.
|
|
1141
1165
|
* Setup methods chain; action methods are terminal: they execute the spec
|
|
@@ -1147,8 +1171,8 @@ interface SpecificationConfig {
|
|
|
1147
1171
|
interface ApiSpecification<DatabaseKey extends string = string> {
|
|
1148
1172
|
/** Set HTTP headers for the request. Multiple calls merge. */
|
|
1149
1173
|
headers: (headers: Record<string, string>) => ApiSpecification<DatabaseKey>;
|
|
1150
|
-
/**
|
|
1151
|
-
intercept:
|
|
1174
|
+
/** Declare outgoing calls — a contract, a list, a composite, or an inline request + response pair. */
|
|
1175
|
+
intercept: InterceptMethod<ApiSpecification<DatabaseKey>>;
|
|
1152
1176
|
/** Queue a SQL seed file from `seeds/` to run before the action. */
|
|
1153
1177
|
seed: (file: string, options?: {
|
|
1154
1178
|
database?: DatabaseKey;
|
|
@@ -1169,8 +1193,8 @@ interface ApiSpecification<DatabaseKey extends string = string> {
|
|
|
1169
1193
|
* Jobs run in-process by definition (CONVENTIONS A5/A8).
|
|
1170
1194
|
*/
|
|
1171
1195
|
interface JobsSpecification<DatabaseKey extends string = string> {
|
|
1172
|
-
/**
|
|
1173
|
-
intercept:
|
|
1196
|
+
/** Declare outgoing calls — a contract, a list, a composite, or an inline request + response pair. */
|
|
1197
|
+
intercept: InterceptMethod<JobsSpecification<DatabaseKey>>;
|
|
1174
1198
|
/** Queue a SQL seed file from `seeds/` to run before the action. */
|
|
1175
1199
|
seed: (file: string, options?: {
|
|
1176
1200
|
database?: DatabaseKey;
|
|
@@ -1217,11 +1241,10 @@ interface WebsiteSpecification {
|
|
|
1217
1241
|
/** Set HTTP headers for the exchange (incl. User-Agent overrides). Multiple calls merge. */
|
|
1218
1242
|
headers: (headers: Record<string, string>) => WebsiteSpecification;
|
|
1219
1243
|
/**
|
|
1220
|
-
* Declare the chain's backend
|
|
1221
|
-
*
|
|
1222
|
-
* `backend` option). Multiple calls layer in order.
|
|
1244
|
+
* Declare the chain's backend contracts — served by the declared stub
|
|
1245
|
+
* backend (requires the runner's `backend` option). Multiple calls append.
|
|
1223
1246
|
*/
|
|
1224
|
-
intercept:
|
|
1247
|
+
intercept: InterceptMethod<WebsiteSpecification>;
|
|
1225
1248
|
/** Perform one raw HTTP GET — redirects surface as 3xx results, never followed. */
|
|
1226
1249
|
fetch: (path: string) => Promise<FetchResult>;
|
|
1227
1250
|
/**
|
|
@@ -1239,11 +1262,10 @@ interface WebsiteSpecification {
|
|
|
1239
1262
|
*/
|
|
1240
1263
|
interface MobileSpecification {
|
|
1241
1264
|
/**
|
|
1242
|
-
* Declare the chain's backend
|
|
1243
|
-
*
|
|
1244
|
-
* `backend` option). Multiple calls layer in order.
|
|
1265
|
+
* Declare the chain's backend contracts — served by the declared stub
|
|
1266
|
+
* backend (requires the runner's `backend` option). Multiple calls append.
|
|
1245
1267
|
*/
|
|
1246
|
-
intercept:
|
|
1268
|
+
intercept: InterceptMethod<MobileSpecification>;
|
|
1247
1269
|
/**
|
|
1248
1270
|
* Relaunch the app and resolve with the captured screen. With a deep
|
|
1249
1271
|
* link, the app opens on it; with a scenario, the visitor interacts
|
|
@@ -1626,8 +1648,8 @@ interface MobileSpecificationOptions {
|
|
|
1626
1648
|
bundleId: string;
|
|
1627
1649
|
};
|
|
1628
1650
|
/**
|
|
1629
|
-
* Declared stub backend: started with the runner, serving the
|
|
1630
|
-
* each chain declares via `.intercept(
|
|
1651
|
+
* Declared stub backend: started with the runner, serving the contracts
|
|
1652
|
+
* each chain declares via `.intercept(...)`. The handle gains
|
|
1631
1653
|
* `backendUrl` — inject it into your bundler env yourself.
|
|
1632
1654
|
*/
|
|
1633
1655
|
backend?: MobileBackendOptions;
|
|
@@ -1685,8 +1707,8 @@ interface ServeOptions {
|
|
|
1685
1707
|
/**
|
|
1686
1708
|
* The declared stub backend behind the site under test — started before the
|
|
1687
1709
|
* server command, torn down with the runner. Its URL is injected into the
|
|
1688
|
-
* server child's environment under `env`; the chain
|
|
1689
|
-
* `.intercept(
|
|
1710
|
+
* server child's environment under `env`; the contracts each chain declares
|
|
1711
|
+
* via `.intercept(...)` are what it serves.
|
|
1690
1712
|
*/
|
|
1691
1713
|
interface WebsiteBackendOptions {
|
|
1692
1714
|
/** Env var receiving the stub's URL in the server child (e.g. `'API_URL'`). */
|
|
@@ -1718,7 +1740,7 @@ type WebsiteSpecificationOptions = {
|
|
|
1718
1740
|
/**
|
|
1719
1741
|
* Declared stub backend: started BEFORE the server command, its
|
|
1720
1742
|
* URL injected into the child env under `backend.env`. Serves the
|
|
1721
|
-
*
|
|
1743
|
+
* contracts each chain declares via `.intercept(...)`.
|
|
1722
1744
|
*/
|
|
1723
1745
|
backend?: WebsiteBackendOptions;
|
|
1724
1746
|
/**
|
|
@@ -2040,20 +2062,38 @@ declare class SqliteHandle implements DatabasePort, ServiceHandle {
|
|
|
2040
2062
|
*/
|
|
2041
2063
|
declare function sqlite(options?: SqliteOptions): SqliteHandle;
|
|
2042
2064
|
//#endregion
|
|
2065
|
+
//#region src/core/contracts/filters.d.ts
|
|
2066
|
+
/**
|
|
2067
|
+
* A text filter on a provider request builder (`openai.chat({ user })`,
|
|
2068
|
+
* `anthropic.messages({ system })`, …).
|
|
2069
|
+
*
|
|
2070
|
+
* A **string is EXACT**. That is deliberate: a substring filter silently
|
|
2071
|
+
* cross-matches — two prompts sharing a preamble both satisfy the first
|
|
2072
|
+
* contract, and the spec goes green on the wrong reply. Looser matching is
|
|
2073
|
+
* explicit, and says which looseness it means:
|
|
2074
|
+
*
|
|
2075
|
+
* - a `RegExp` — pattern matching;
|
|
2076
|
+
* - `match.includes('…')` — containment, the code-only matcher (it never joins
|
|
2077
|
+
* the `{{token}}` file vocabulary, CONVENTIONS D4);
|
|
2078
|
+
* - any other `match.*` matcher, evaluated by the same structural engine the
|
|
2079
|
+
* assertions use.
|
|
2080
|
+
*/
|
|
2081
|
+
type TextFilter = Matcher | RegExp | string;
|
|
2082
|
+
//#endregion
|
|
2043
2083
|
//#region src/integrations/anthropic/anthropic.d.ts
|
|
2044
2084
|
interface AnthropicMessagesFilter {
|
|
2045
|
-
model?:
|
|
2046
|
-
system?:
|
|
2047
|
-
user?:
|
|
2085
|
+
model?: TextFilter;
|
|
2086
|
+
system?: TextFilter;
|
|
2087
|
+
user?: TextFilter;
|
|
2048
2088
|
tools?: string[];
|
|
2049
2089
|
}
|
|
2050
|
-
declare function buildReply(data: unknown):
|
|
2090
|
+
declare function buildReply(data: unknown): ContractResponse;
|
|
2051
2091
|
/**
|
|
2052
2092
|
* Anthropic API intercept helpers.
|
|
2053
2093
|
*/
|
|
2054
2094
|
declare const anthropic: {
|
|
2055
2095
|
/**
|
|
2056
|
-
*
|
|
2096
|
+
* Request: match Messages API calls, optionally routed through a
|
|
2057
2097
|
* custom gateway URL. When used with a JSON fixture file, the data is
|
|
2058
2098
|
* returned as-is (no wrapping) because Anthropic fixtures are typically
|
|
2059
2099
|
* already in the Messages API response shape.
|
|
@@ -2061,15 +2101,16 @@ declare const anthropic: {
|
|
|
2061
2101
|
* @example
|
|
2062
2102
|
* anthropic.messages()
|
|
2063
2103
|
* anthropic.messages({ system: /classify/ })
|
|
2104
|
+
* anthropic.messages({ user: buildPrompt() }) // string = EXACT equality
|
|
2064
2105
|
* anthropic.messages({ user: /classify/ }, GATEWAY)
|
|
2065
2106
|
*/
|
|
2066
|
-
messages(filter?: AnthropicMessagesFilter, url?: string):
|
|
2107
|
+
messages(filter?: AnthropicMessagesFilter, url?: string): ContractRequest;
|
|
2067
2108
|
/** Response: wrap data in Anthropic messages format. */
|
|
2068
2109
|
reply: typeof buildReply;
|
|
2069
2110
|
/** Response: return an Anthropic error. */
|
|
2070
|
-
error(status: number, message?: string):
|
|
2111
|
+
error(status: number, message?: string): ContractResponse;
|
|
2071
2112
|
/** Response: simulate a timeout. */
|
|
2072
|
-
timeout():
|
|
2113
|
+
timeout(): ContractResponse;
|
|
2073
2114
|
};
|
|
2074
2115
|
//#endregion
|
|
2075
2116
|
//#region src/core/contracts/http.d.ts
|
|
@@ -2077,7 +2118,7 @@ declare const anthropic: {
|
|
|
2077
2118
|
* Request filters for the generic HTTP provider. Every field is a subset
|
|
2078
2119
|
* constraint — a request matches when all provided fields match.
|
|
2079
2120
|
*/
|
|
2080
|
-
interface
|
|
2121
|
+
interface HttpContractFilter {
|
|
2081
2122
|
/**
|
|
2082
2123
|
* Body constraint. An object is a deep SUBSET match (toMatchObject-style)
|
|
2083
2124
|
* whose leaf values may be `match.*` matchers; a string is a containment
|
|
@@ -2089,58 +2130,78 @@ interface HttpInterceptFilter {
|
|
|
2089
2130
|
/** Query-param subset. string = exact value, RegExp = `test()`. */
|
|
2090
2131
|
query?: Record<string, RegExp | string>;
|
|
2091
2132
|
}
|
|
2133
|
+
/** Init options shared by the response builders. */
|
|
2134
|
+
interface HttpResponseInit {
|
|
2135
|
+
/** Delay in ms before responding (for timeout testing). */
|
|
2136
|
+
delay?: number;
|
|
2137
|
+
/** Response headers, merged over the builder's own. */
|
|
2138
|
+
headers?: Record<string, string>;
|
|
2139
|
+
/** HTTP status code. */
|
|
2140
|
+
status?: number;
|
|
2141
|
+
}
|
|
2092
2142
|
/**
|
|
2093
|
-
* Generic HTTP
|
|
2094
|
-
*
|
|
2095
|
-
*
|
|
2096
|
-
*
|
|
2143
|
+
* Generic HTTP contract helpers for any URL. The url is absolute (string or
|
|
2144
|
+
* RegExp), or a PATH FORM starting with `/` — `http.get('/articles/{{uuid}}')`
|
|
2145
|
+
* matches that path on ANY origin, which is what an app calling its own
|
|
2146
|
+
* backend needs. An optional {@link HttpContractFilter} narrows matching by
|
|
2147
|
+
* body, headers, or query — a request that hits the URL/method but fails the
|
|
2148
|
+
* filter counts as unmatched (strict contracts, CONVENTIONS D7).
|
|
2097
2149
|
*
|
|
2098
2150
|
* @example
|
|
2099
|
-
*
|
|
2100
|
-
*
|
|
2151
|
+
* defineContract({ request: http.get('/articles/{{uuid}}'), response: http.json(article) })
|
|
2152
|
+
* defineContract({ request: http.post(URL, { body: { user: 'alice' } }), response: http.empty() })
|
|
2101
2153
|
*/
|
|
2102
2154
|
declare const http: {
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
error
|
|
2155
|
+
any(url: RegExp | string, filter?: HttpContractFilter): ContractRequest;
|
|
2156
|
+
delete(url: RegExp | string, filter?: HttpContractFilter): ContractRequest;
|
|
2157
|
+
get(url: RegExp | string, filter?: HttpContractFilter): ContractRequest;
|
|
2158
|
+
patch(url: RegExp | string, filter?: HttpContractFilter): ContractRequest;
|
|
2159
|
+
post(url: RegExp | string, filter?: HttpContractFilter): ContractRequest;
|
|
2160
|
+
put(url: RegExp | string, filter?: HttpContractFilter): ContractRequest;
|
|
2161
|
+
/** Response: a body-less reply (204 by default). */
|
|
2162
|
+
empty(status?: number): ContractResponse;
|
|
2163
|
+
/** Response: an error status. Without a body, `{ error: 'HTTP <status>' }`. */
|
|
2164
|
+
error(status: number, body?: unknown): ContractResponse;
|
|
2165
|
+
/** Response: a JSON body (200 by default). */
|
|
2166
|
+
json(body: unknown, init?: HttpResponseInit): ContractResponse;
|
|
2167
|
+
/** Response: a text body, served as `text/plain` (200 by default). */
|
|
2168
|
+
text(body: string, init?: HttpResponseInit): ContractResponse;
|
|
2112
2169
|
};
|
|
2113
2170
|
//#endregion
|
|
2114
2171
|
//#region src/integrations/openai/openai.d.ts
|
|
2115
2172
|
interface OpenAIChatFilter {
|
|
2116
|
-
model?:
|
|
2117
|
-
system?:
|
|
2118
|
-
user?:
|
|
2173
|
+
model?: TextFilter;
|
|
2174
|
+
system?: TextFilter;
|
|
2175
|
+
user?: TextFilter;
|
|
2119
2176
|
tools?: string[];
|
|
2120
2177
|
temperature?: number;
|
|
2121
2178
|
}
|
|
2122
2179
|
interface OpenAIResponsesFilter {
|
|
2123
|
-
model?:
|
|
2124
|
-
system?:
|
|
2125
|
-
user?:
|
|
2180
|
+
model?: TextFilter;
|
|
2181
|
+
system?: TextFilter;
|
|
2182
|
+
user?: TextFilter;
|
|
2126
2183
|
tools?: string[];
|
|
2127
2184
|
}
|
|
2128
|
-
declare function buildChatReply(data: unknown):
|
|
2185
|
+
declare function buildChatReply(data: unknown): ContractResponse;
|
|
2129
2186
|
/**
|
|
2130
2187
|
* OpenAI API intercept helpers.
|
|
2131
2188
|
*/
|
|
2132
2189
|
declare const openai: {
|
|
2133
2190
|
/**
|
|
2134
|
-
*
|
|
2191
|
+
* Request: match Chat Completions API calls. STRING filters mean EXACT
|
|
2192
|
+
* equality (pass the app's own prompt builder); loosen deliberately with a
|
|
2193
|
+
* RegExp or `match.includes(...)`.
|
|
2135
2194
|
*
|
|
2136
2195
|
* @example
|
|
2137
|
-
* openai.chat()
|
|
2138
|
-
* openai.chat({ model: 'gpt-4o' })
|
|
2139
|
-
* openai.chat({ system:
|
|
2196
|
+
* openai.chat() // any chat call
|
|
2197
|
+
* openai.chat({ model: 'gpt-4o' }) // exact model
|
|
2198
|
+
* openai.chat({ system: buildPrompt() }) // exact system prompt
|
|
2199
|
+
* openai.chat({ system: /classify/ }) // pattern
|
|
2140
2200
|
*/
|
|
2141
|
-
chat(filter?: OpenAIChatFilter):
|
|
2201
|
+
chat(filter?: OpenAIChatFilter): ContractRequest;
|
|
2142
2202
|
/**
|
|
2143
|
-
*
|
|
2203
|
+
* Request: match Responses API calls (AI SDK v5+) with auto-wrapping.
|
|
2204
|
+
* String filters mean EXACT equality (see {@link openai.chat}).
|
|
2144
2205
|
* When used with a JSON file, the data is automatically wrapped in the
|
|
2145
2206
|
* Responses API envelope.
|
|
2146
2207
|
*
|
|
@@ -2150,7 +2211,7 @@ declare const openai: {
|
|
|
2150
2211
|
* @example
|
|
2151
2212
|
* openai.responses({ user: /Report Ingestion/ }, GATEWAY)
|
|
2152
2213
|
*/
|
|
2153
|
-
responses(filter?: OpenAIResponsesFilter, url?: string):
|
|
2214
|
+
responses(filter?: OpenAIResponsesFilter, url?: string): ContractRequest;
|
|
2154
2215
|
/**
|
|
2155
2216
|
* Response: wrap data in Chat Completions format.
|
|
2156
2217
|
*
|
|
@@ -2159,11 +2220,11 @@ declare const openai: {
|
|
|
2159
2220
|
*/
|
|
2160
2221
|
reply: typeof buildChatReply;
|
|
2161
2222
|
/** Response: return an OpenAI error. */
|
|
2162
|
-
error(status: number, message?: string):
|
|
2223
|
+
error(status: number, message?: string): ContractResponse;
|
|
2163
2224
|
/** Response: return malformed content. */
|
|
2164
|
-
malformed(content: string):
|
|
2225
|
+
malformed(content: string): ContractResponse;
|
|
2165
2226
|
/** Response: simulate a timeout. */
|
|
2166
|
-
timeout():
|
|
2227
|
+
timeout(): ContractResponse;
|
|
2167
2228
|
};
|
|
2168
2229
|
//#endregion
|
|
2169
2230
|
//#region src/vitest/mock-of.d.ts
|
|
@@ -2229,4 +2290,4 @@ declare module 'vitest' {
|
|
|
2229
2290
|
}
|
|
2230
2291
|
}
|
|
2231
2292
|
//#endregion
|
|
2232
|
-
export { type ApiHandle, type ApiSpecification, type ApiSpecificationOptions, BaseResult, type BrowserConsoleMessage, type BrowserLinkElement, type BrowserMetaElement, type BrowserOpenOptions, type BrowserPage, type BrowserPort, type CaptureScope, type CliEnv, type CliHandle, type CliOutput, type CliPort, CliResult, type CliSpecification, type CliSpecificationOptions, ContainerAccessor, type ContainerPort, type DatabaseKeys, type DatabasePort, type DeviceOpenOptions, type DevicePort, type DeviceScreen, DirectoryAccessor, type DockerSpecConfig, type ElementKind, type ElementMatch, type ElementOptions, type ElementRef, type ExecOptions, FetchResult, type FileAccessor, FilesystemAccessor, type HonoApp,
|
|
2293
|
+
export { type ApiHandle, type ApiSpecification, type ApiSpecificationOptions, BaseResult, type BrowserConsoleMessage, type BrowserLinkElement, type BrowserMetaElement, type BrowserOpenOptions, type BrowserPage, type BrowserPort, type CaptureScope, type CliEnv, type CliHandle, type CliOutput, type CliPort, CliResult, type CliSpecification, type CliSpecificationOptions, ContainerAccessor, type ContainerPort, type Contract, type ContractInput, type ContractRequest, type ContractResponder, type ContractResponse, type ContractResponseValue, type Contracts, type DatabaseKeys, type DatabasePort, type DeviceOpenOptions, type DevicePort, type DeviceScreen, DirectoryAccessor, type DockerSpecConfig, type ElementKind, type ElementMatch, type ElementOptions, type ElementRef, type ExecOptions, FetchResult, type FileAccessor, FilesystemAccessor, type HonoApp, type HttpContractFilter, type HttpResponseInit, HttpResult, type IsolationStrategy, type JobHandle, type JobsHandle, type JobsSpecification, type JobsSpecificationOptions, JsonAccessor, type LandmarkKind, type MatchFixtureOptions, type MatchableRequest, Matcher, type MatcherKind, type MobileBackendOptions, type MobileElementKind, type MobileElementMatch, type MobileElementRef, type MobileHandle, type MobileScenario, type MobileSpecification, type MobileSpecificationOptions, type MobileVisitor, type MockDatePort, type MockPort, Orchestrator, PageResult, type PostgresOptions, type RedisOptions, ResponseAccessor, type ScreenNode, ScreenResult, type ServeOptions, type ServerPort, type ServerResponse, type ServiceHandle, type ServiceRecord, type SpecificationConfig, type SpecificationMode, type SqliteOptions, TableAccessor, TextAccessor, type TextFilter, type VisitScenario, type Visitor, type WebsiteBackendOptions, type WebsiteHandle, type WebsiteSpecification, type WebsiteSpecificationOptions, anthropic, banner, button, complementary, content, contentinfo, defineContract, defineContracts, field, findContainersByLabel, form, heading, http, inspectContainer, link, main, match, mockOf, mockOfDate, navigation, openai, postgres, redis, region, removeContainers, search, specification, sqlite, testId, text, within };
|