@jterrazz/test 10.0.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 +101 -35
- package/dist/ambiguity.js +126 -0
- package/dist/appium.adapter.js +399 -0
- package/dist/checker.js +0 -1
- package/dist/index.d.ts +500 -101
- package/dist/index.js +587 -464
- package/dist/intercept.js +37 -84
- package/dist/match.js +12 -1
- package/dist/oxlint.cjs +420 -117
- package/dist/oxlint.d.cts +1 -1
- package/dist/oxlint.d.ts +1 -1
- package/dist/oxlint.js +420 -117
- package/dist/playwright.adapter.js +3 -127
- package/dist/queue.js +555 -0
- package/package.json +13 -4
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
|
|
440
|
-
*/
|
|
441
|
-
type InterceptResponder = (request: MatchableRequest) => InterceptResponse;
|
|
442
|
-
/**
|
|
443
|
-
* What an intercept replies with: either a fixed {@link InterceptResponse} or
|
|
444
|
-
* an {@link InterceptResponder} evaluated per consumed request.
|
|
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.
|
|
445
455
|
*/
|
|
446
|
-
type
|
|
456
|
+
type ContractResponder = (request: MatchableRequest) => ContractResponse;
|
|
447
457
|
/**
|
|
448
|
-
*
|
|
458
|
+
* What a contract replies with: either a fixed {@link ContractResponse} or a
|
|
459
|
+
* {@link ContractResponder} evaluated per served request.
|
|
449
460
|
*/
|
|
450
|
-
|
|
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
|
/**
|
|
@@ -591,6 +640,11 @@ interface Visitor {
|
|
|
591
640
|
type VisitScenario = (visitor: Visitor) => Promise<void>;
|
|
592
641
|
/** Per-visit options forwarded to the browser context. */
|
|
593
642
|
interface BrowserOpenOptions {
|
|
643
|
+
/**
|
|
644
|
+
* Extra origins the `external: 'block'` policy lets through — the
|
|
645
|
+
* declared stub backend the page legitimately fetches from.
|
|
646
|
+
*/
|
|
647
|
+
allowedOrigins?: string[];
|
|
594
648
|
/**
|
|
595
649
|
* Base URL of the site under test — the origin `goto()` resolves against
|
|
596
650
|
* and the boundary of the `external` policy.
|
|
@@ -644,6 +698,107 @@ interface BrowserPort {
|
|
|
644
698
|
open: (url: string, options: BrowserOpenOptions) => Promise<BrowserPage>;
|
|
645
699
|
}
|
|
646
700
|
//#endregion
|
|
701
|
+
//#region src/core/ports/device.port.d.ts
|
|
702
|
+
/**
|
|
703
|
+
* The element kinds a mobile screen can designate — the structural subset of
|
|
704
|
+
* {@link ElementRef} kinds that map onto the XCUITest accessibility tree.
|
|
705
|
+
* There is ONE element vocabulary across facets: `button('Bookmark')` works
|
|
706
|
+
* in a visit scenario and a mobile scenario alike. Landmarks have no iOS
|
|
707
|
+
* analog — passing one to a mobile verb refuses at runtime.
|
|
708
|
+
*/
|
|
709
|
+
type MobileElementKind = 'button' | 'field' | 'testId' | 'text';
|
|
710
|
+
/**
|
|
711
|
+
* A user-facing element descriptor for mobile scenarios — pure data, built by
|
|
712
|
+
* the shared element vocabulary (`button()`, `field()`, `content()`,
|
|
713
|
+
* `testId()`, `within()`) and translated into iOS predicate strings by the
|
|
714
|
+
* device integration. Structurally the same ref type as the browser's, so the
|
|
715
|
+
* vocabulary stays single; kinds outside {@link MobileElementKind} (the ARIA
|
|
716
|
+
* landmarks) are refused at runtime with a message naming the boundary.
|
|
717
|
+
*
|
|
718
|
+
* A descriptor must designate exactly ONE element when a verb ACTS on it
|
|
719
|
+
* (`tap`, `fill`) — see {@link MobileElementMatch} and CONVENTIONS W3.
|
|
720
|
+
* `see()` acts on nothing, so any visible match satisfies it: XCUITest trees
|
|
721
|
+
* legitimately duplicate a label across container and child.
|
|
722
|
+
*/
|
|
723
|
+
type MobileElementRef = ElementRef;
|
|
724
|
+
/**
|
|
725
|
+
* One candidate captured when a descriptor matched more than one element —
|
|
726
|
+
* the evidence the ambiguity error enumerates so the author can disambiguate
|
|
727
|
+
* without opening the simulator.
|
|
728
|
+
*/
|
|
729
|
+
interface MobileElementMatch {
|
|
730
|
+
/** The accessibility identifier (`testId()` target), when one is set. */
|
|
731
|
+
identifier?: string;
|
|
732
|
+
/** The accessible label, whitespace-collapsed and truncated. */
|
|
733
|
+
label?: string;
|
|
734
|
+
/** Element type without the `XCUIElementType` prefix — `Button`, `StaticText`. */
|
|
735
|
+
type: string;
|
|
736
|
+
/** The element value (text-field content, adjustable value), when present. */
|
|
737
|
+
value?: string;
|
|
738
|
+
}
|
|
739
|
+
/**
|
|
740
|
+
* The visitor — the interaction vocabulary handed to a mobile scenario.
|
|
741
|
+
* Every verb auto-waits by polling until a visible match exists; acting
|
|
742
|
+
* verbs then enforce exactly-one (W3), while `see()` — the single
|
|
743
|
+
* synchronization primitive — is satisfied by any visible match. There is
|
|
744
|
+
* no sleep and no conditional helper.
|
|
745
|
+
*/
|
|
746
|
+
interface MobileVisitor {
|
|
747
|
+
/** Fill a text field with a value. */
|
|
748
|
+
fill: (element: MobileElementRef, value: string) => Promise<void>;
|
|
749
|
+
/** Wait until the element is visible — the only synchronization primitive. */
|
|
750
|
+
see: (element: MobileElementRef) => Promise<void>;
|
|
751
|
+
/** Tap the element. */
|
|
752
|
+
tap: (element: MobileElementRef) => Promise<void>;
|
|
753
|
+
}
|
|
754
|
+
/** The behavior of an open — the When of the spec; assertions stay in the Then. */
|
|
755
|
+
type MobileScenario = (visitor: MobileVisitor) => Promise<void>;
|
|
756
|
+
/**
|
|
757
|
+
* One node of the projected accessibility tree — the XCUITest page source
|
|
758
|
+
* with its noise collapsed: unlabeled, identifier-less, valueless wrapper
|
|
759
|
+
* nodes are dropped and their children hoisted, so the projection stays
|
|
760
|
+
* stable and golden-friendly. Type names lose the `XCUIElementType` prefix.
|
|
761
|
+
*/
|
|
762
|
+
interface ScreenNode {
|
|
763
|
+
children?: ScreenNode[];
|
|
764
|
+
/** The accessibility identifier, only when it differs from the label. */
|
|
765
|
+
identifier?: string;
|
|
766
|
+
label?: string;
|
|
767
|
+
/** Element type without the `XCUIElementType` prefix — `Button`, `StaticText`. */
|
|
768
|
+
type: string;
|
|
769
|
+
value?: string;
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* The screen captured by a device open — the FINAL state when a scenario
|
|
773
|
+
* ran. The tree is the projected page source; `texts` are the visible
|
|
774
|
+
* labels/values in document order, consecutive duplicates collapsed.
|
|
775
|
+
*/
|
|
776
|
+
interface DeviceScreen {
|
|
777
|
+
texts: string[];
|
|
778
|
+
tree: ScreenNode;
|
|
779
|
+
}
|
|
780
|
+
/** Per-open options forwarded to the device session. */
|
|
781
|
+
interface DeviceOpenOptions {
|
|
782
|
+
/** The app under test — terminated and relaunched for a fresh, deterministic state. */
|
|
783
|
+
bundleId: string;
|
|
784
|
+
/** Deep link applied after the relaunch (`news://events`); absent opens the app plainly. */
|
|
785
|
+
deepLink?: string;
|
|
786
|
+
/** The interaction scenario to run after launch; the capture reflects the final state. */
|
|
787
|
+
scenario?: MobileScenario;
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* Abstract device interface for the mobile specification runner.
|
|
791
|
+
* One implementation lives in `integrations/appium/` — a single driver
|
|
792
|
+
* session per runner, created on the first `open()` and reused; each open
|
|
793
|
+
* terminates and relaunches the app for a deterministic fresh state.
|
|
794
|
+
*/
|
|
795
|
+
interface DevicePort {
|
|
796
|
+
/** End the driver session (idempotent). */
|
|
797
|
+
close: () => Promise<void>;
|
|
798
|
+
/** Relaunch the app, apply the deep link, run the scenario, capture the final screen. */
|
|
799
|
+
open: (options: DeviceOpenOptions) => Promise<DeviceScreen>;
|
|
800
|
+
}
|
|
801
|
+
//#endregion
|
|
647
802
|
//#region src/core/ports/isolation.port.d.ts
|
|
648
803
|
/**
|
|
649
804
|
* Strategy for isolating service state across parallel test workers.
|
|
@@ -771,6 +926,27 @@ declare class HttpResult extends BaseResult {
|
|
|
771
926
|
get status(): number;
|
|
772
927
|
}
|
|
773
928
|
//#endregion
|
|
929
|
+
//#region src/core/specification/mobile/result.d.ts
|
|
930
|
+
/** Result from a `.open()` action — the screen as the device saw it, final state. */
|
|
931
|
+
declare class ScreenResult extends BaseResult {
|
|
932
|
+
private readonly capturedScreen;
|
|
933
|
+
constructor(options: {
|
|
934
|
+
config: SpecificationConfig;
|
|
935
|
+
screen: DeviceScreen;
|
|
936
|
+
testDir: string;
|
|
937
|
+
});
|
|
938
|
+
/**
|
|
939
|
+
* The visible screen texts as one stream, in reading order — the scalpel
|
|
940
|
+
* for a targeted probe: `expect(result.content).toContain('Bookmarked')`.
|
|
941
|
+
*/
|
|
942
|
+
get content(): TextAccessor;
|
|
943
|
+
/**
|
|
944
|
+
* The projected accessibility tree as a JSON accessor — the one golden
|
|
945
|
+
* per screen: `expect(result.screen).toMatch('events.screen.json')`.
|
|
946
|
+
*/
|
|
947
|
+
get screen(): JsonAccessor;
|
|
948
|
+
}
|
|
949
|
+
//#endregion
|
|
774
950
|
//#region src/core/specification/website/result.d.ts
|
|
775
951
|
/** A raw HTTP exchange captured by `.fetch()` — redirects are NOT followed. */
|
|
776
952
|
interface FetchExchange {
|
|
@@ -848,6 +1024,48 @@ declare class PageResult extends BaseResult {
|
|
|
848
1024
|
get url(): string;
|
|
849
1025
|
}
|
|
850
1026
|
//#endregion
|
|
1027
|
+
//#region src/core/specification/shared/stub-backend.d.ts
|
|
1028
|
+
/** Options for the stub backend server. */
|
|
1029
|
+
interface StubBackendOptions {
|
|
1030
|
+
/**
|
|
1031
|
+
* Fixed port — pins a stable stub URL across runs (a bundler that inlines
|
|
1032
|
+
* the URL at serve time survives warm). Default: a free OS-assigned port.
|
|
1033
|
+
*/
|
|
1034
|
+
port?: number;
|
|
1035
|
+
}
|
|
1036
|
+
declare class StubBackend {
|
|
1037
|
+
/** Guarded once the current chain declared at least one contract. */
|
|
1038
|
+
private guarded;
|
|
1039
|
+
private readonly options;
|
|
1040
|
+
private queue;
|
|
1041
|
+
private server;
|
|
1042
|
+
private readonly unmatchedRequests;
|
|
1043
|
+
private url;
|
|
1044
|
+
constructor(options?: StubBackendOptions);
|
|
1045
|
+
/** Start the server and resolve with its base URL. */
|
|
1046
|
+
start(): Promise<string>;
|
|
1047
|
+
/** Stop the server (idempotent). */
|
|
1048
|
+
stop(): Promise<void>;
|
|
1049
|
+
/**
|
|
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 —
|
|
1052
|
+
* the reset-between-chains databases already follow.
|
|
1053
|
+
*/
|
|
1054
|
+
beginChain(contracts: readonly Contract[]): void;
|
|
1055
|
+
/**
|
|
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.
|
|
1061
|
+
*/
|
|
1062
|
+
violation(): Error | null;
|
|
1063
|
+
private corsHeaders;
|
|
1064
|
+
private describeRoutes;
|
|
1065
|
+
private handle;
|
|
1066
|
+
private record;
|
|
1067
|
+
}
|
|
1068
|
+
//#endregion
|
|
851
1069
|
//#region src/core/specification/shared/builder.d.ts
|
|
852
1070
|
/** A named job that can be triggered via jobs.trigger(). */
|
|
853
1071
|
interface JobHandle {
|
|
@@ -867,6 +1085,16 @@ interface DockerSpecConfig {
|
|
|
867
1085
|
}
|
|
868
1086
|
/** Adapter configuration passed to the specification facets at setup time. */
|
|
869
1087
|
interface SpecificationConfig {
|
|
1088
|
+
/**
|
|
1089
|
+
* The declared stub backend (website/mobile facets) — armed with the
|
|
1090
|
+
* chain's contracts before every terminal action.
|
|
1091
|
+
*/
|
|
1092
|
+
backend?: StubBackend;
|
|
1093
|
+
/**
|
|
1094
|
+
* Base URL of the running stub backend — allow-listed through the
|
|
1095
|
+
* browser's `external: 'block'` policy so client-side fetches reach it.
|
|
1096
|
+
*/
|
|
1097
|
+
backendUrl?: string;
|
|
870
1098
|
/** Base URL of the website under test (website facet only). */
|
|
871
1099
|
baseUrl?: string;
|
|
872
1100
|
/**
|
|
@@ -881,6 +1109,8 @@ interface SpecificationConfig {
|
|
|
881
1109
|
* of strict intercepts.
|
|
882
1110
|
*/
|
|
883
1111
|
external?: 'allow' | 'block';
|
|
1112
|
+
/** Bundle id of the app under test (mobile facet only) — the app `.open()` relaunches. */
|
|
1113
|
+
bundleId?: string;
|
|
884
1114
|
command?: CliPort;
|
|
885
1115
|
database?: DatabasePort;
|
|
886
1116
|
/**
|
|
@@ -890,6 +1120,13 @@ interface SpecificationConfig {
|
|
|
890
1120
|
*/
|
|
891
1121
|
databaseKeys?: string[];
|
|
892
1122
|
databases?: Map<string, DatabasePort>;
|
|
1123
|
+
/**
|
|
1124
|
+
* Lazy device accessor (mobile facet only). The first `.open()` creates
|
|
1125
|
+
* the shared driver session; the appium/webdriverio integration stays a
|
|
1126
|
+
* lazy import so the optional peer is only loaded when a spec opens the
|
|
1127
|
+
* app.
|
|
1128
|
+
*/
|
|
1129
|
+
device?: () => Promise<DevicePort>;
|
|
893
1130
|
dockerConfig?: DockerSpecConfig;
|
|
894
1131
|
/**
|
|
895
1132
|
* Unique id shared by every spec from this runner instance.
|
|
@@ -918,6 +1155,11 @@ interface SpecificationConfig {
|
|
|
918
1155
|
*/
|
|
919
1156
|
transform?: (text: string) => string;
|
|
920
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);
|
|
921
1163
|
/**
|
|
922
1164
|
* The `api` facet — HTTP chain entry handed out by `specification.api()`.
|
|
923
1165
|
* Setup methods chain; action methods are terminal: they execute the spec
|
|
@@ -929,8 +1171,8 @@ interface SpecificationConfig {
|
|
|
929
1171
|
interface ApiSpecification<DatabaseKey extends string = string> {
|
|
930
1172
|
/** Set HTTP headers for the request. Multiple calls merge. */
|
|
931
1173
|
headers: (headers: Record<string, string>) => ApiSpecification<DatabaseKey>;
|
|
932
|
-
/**
|
|
933
|
-
intercept:
|
|
1174
|
+
/** Declare outgoing calls — a contract, a list, a composite, or an inline request + response pair. */
|
|
1175
|
+
intercept: InterceptMethod<ApiSpecification<DatabaseKey>>;
|
|
934
1176
|
/** Queue a SQL seed file from `seeds/` to run before the action. */
|
|
935
1177
|
seed: (file: string, options?: {
|
|
936
1178
|
database?: DatabaseKey;
|
|
@@ -951,8 +1193,8 @@ interface ApiSpecification<DatabaseKey extends string = string> {
|
|
|
951
1193
|
* Jobs run in-process by definition (CONVENTIONS A5/A8).
|
|
952
1194
|
*/
|
|
953
1195
|
interface JobsSpecification<DatabaseKey extends string = string> {
|
|
954
|
-
/**
|
|
955
|
-
intercept:
|
|
1196
|
+
/** Declare outgoing calls — a contract, a list, a composite, or an inline request + response pair. */
|
|
1197
|
+
intercept: InterceptMethod<JobsSpecification<DatabaseKey>>;
|
|
956
1198
|
/** Queue a SQL seed file from `seeds/` to run before the action. */
|
|
957
1199
|
seed: (file: string, options?: {
|
|
958
1200
|
database?: DatabaseKey;
|
|
@@ -998,6 +1240,11 @@ interface CliSpecification<DatabaseKey extends string = string> {
|
|
|
998
1240
|
interface WebsiteSpecification {
|
|
999
1241
|
/** Set HTTP headers for the exchange (incl. User-Agent overrides). Multiple calls merge. */
|
|
1000
1242
|
headers: (headers: Record<string, string>) => WebsiteSpecification;
|
|
1243
|
+
/**
|
|
1244
|
+
* Declare the chain's backend contracts — served by the declared stub
|
|
1245
|
+
* backend (requires the runner's `backend` option). Multiple calls append.
|
|
1246
|
+
*/
|
|
1247
|
+
intercept: InterceptMethod<WebsiteSpecification>;
|
|
1001
1248
|
/** Perform one raw HTTP GET — redirects surface as 3xx results, never followed. */
|
|
1002
1249
|
fetch: (path: string) => Promise<FetchResult>;
|
|
1003
1250
|
/**
|
|
@@ -1007,6 +1254,25 @@ interface WebsiteSpecification {
|
|
|
1007
1254
|
*/
|
|
1008
1255
|
visit: (path: string, scenario?: VisitScenario) => Promise<PageResult>;
|
|
1009
1256
|
}
|
|
1257
|
+
/**
|
|
1258
|
+
* The `mobile` facet — screen chain entry handed out by
|
|
1259
|
+
* `specification.mobile()`. `.open()` is the single, terminal action: it
|
|
1260
|
+
* terminates and relaunches the app (deterministic fresh state), applies the
|
|
1261
|
+
* deep link, runs the scenario, and captures the final screen.
|
|
1262
|
+
*/
|
|
1263
|
+
interface MobileSpecification {
|
|
1264
|
+
/**
|
|
1265
|
+
* Declare the chain's backend contracts — served by the declared stub
|
|
1266
|
+
* backend (requires the runner's `backend` option). Multiple calls append.
|
|
1267
|
+
*/
|
|
1268
|
+
intercept: InterceptMethod<MobileSpecification>;
|
|
1269
|
+
/**
|
|
1270
|
+
* Relaunch the app and resolve with the captured screen. With a deep
|
|
1271
|
+
* link, the app opens on it; with a scenario, the visitor interacts
|
|
1272
|
+
* first (the When) and the capture reflects the FINAL screen state.
|
|
1273
|
+
*/
|
|
1274
|
+
open: (deepLink?: string, scenario?: MobileScenario) => Promise<ScreenResult>;
|
|
1275
|
+
}
|
|
1010
1276
|
//#endregion
|
|
1011
1277
|
//#region src/core/specification/cli/result.d.ts
|
|
1012
1278
|
/**
|
|
@@ -1358,6 +1624,72 @@ interface JobsHandle<DatabaseKey extends string = string> {
|
|
|
1358
1624
|
}
|
|
1359
1625
|
declare function startJobs<Services extends ServiceRecord>(options: JobsSpecificationOptions<Services>): Promise<JobsHandle<DatabaseKeys<Services>>>;
|
|
1360
1626
|
//#endregion
|
|
1627
|
+
//#region src/core/specification/mobile/start-mobile.d.ts
|
|
1628
|
+
/**
|
|
1629
|
+
* The declared stub backend behind the app under test. The framework owns
|
|
1630
|
+
* the simulator and appium but NOT the JS bundler (Metro belongs to the
|
|
1631
|
+
* caller's repo, like `next build` belongs to a website's) — so nothing is
|
|
1632
|
+
* injected: the handle exposes `backendUrl` and the CALLER wires it into its
|
|
1633
|
+
* own bundler env.
|
|
1634
|
+
*/
|
|
1635
|
+
interface MobileBackendOptions {
|
|
1636
|
+
/**
|
|
1637
|
+
* Fixed port — pins a stable stub URL across runs. Metro inlines
|
|
1638
|
+
* `EXPO_PUBLIC_*` values at bundle-serve time; a stable port lets a warm
|
|
1639
|
+
* Metro survive between runs. Default: a free OS-assigned port.
|
|
1640
|
+
*/
|
|
1641
|
+
port?: number;
|
|
1642
|
+
}
|
|
1643
|
+
/** Options for {@link startMobile | specification.mobile}. */
|
|
1644
|
+
interface MobileSpecificationOptions {
|
|
1645
|
+
/** The app under test — terminated and relaunched by every `.open()`. */
|
|
1646
|
+
app: {
|
|
1647
|
+
/** Bundle id of the installed app (`com.example.app`). */
|
|
1648
|
+
bundleId: string;
|
|
1649
|
+
};
|
|
1650
|
+
/**
|
|
1651
|
+
* Declared stub backend: started with the runner, serving the contracts
|
|
1652
|
+
* each chain declares via `.intercept(...)`. The handle gains
|
|
1653
|
+
* `backendUrl` — inject it into your bundler env yourself.
|
|
1654
|
+
*/
|
|
1655
|
+
backend?: MobileBackendOptions;
|
|
1656
|
+
/** The simulator to run on — resolved through `xcrun simctl`. */
|
|
1657
|
+
device: {
|
|
1658
|
+
/** Simulator name, matched exactly (`iPhone 17`). */
|
|
1659
|
+
name: string;
|
|
1660
|
+
/** OS narrowing when the name exists on several runtimes — `'26.5'` or `'iOS 26.5'`. */
|
|
1661
|
+
os?: string;
|
|
1662
|
+
/** Explicit UDID — skips name/os resolution entirely. */
|
|
1663
|
+
udid?: string;
|
|
1664
|
+
};
|
|
1665
|
+
/**
|
|
1666
|
+
* Project-root override (CONVENTIONS A9): where the appium binary is
|
|
1667
|
+
* resolved from (`node_modules/.bin`). Auto-discovered from the calling
|
|
1668
|
+
* file when absent.
|
|
1669
|
+
*/
|
|
1670
|
+
root?: string;
|
|
1671
|
+
}
|
|
1672
|
+
/**
|
|
1673
|
+
* The record returned by {@link startMobile | specification.mobile}.
|
|
1674
|
+
* Destructure with the canonical names (CONVENTIONS A3):
|
|
1675
|
+
*
|
|
1676
|
+
* const { mobile, cleanup, udid } = await specification.mobile(…);
|
|
1677
|
+
*/
|
|
1678
|
+
interface MobileHandle {
|
|
1679
|
+
/**
|
|
1680
|
+
* Base URL of the declared stub backend — present only with the
|
|
1681
|
+
* `backend` option. The caller injects it into its own bundler env
|
|
1682
|
+
* (e.g. `EXPO_PUBLIC_API_URL`); the framework never touches the bundler.
|
|
1683
|
+
*/
|
|
1684
|
+
backendUrl?: string;
|
|
1685
|
+
/** End the driver session, stop the appium server and the stub backend. */
|
|
1686
|
+
cleanup: () => Promise<void>;
|
|
1687
|
+
mobile: MobileSpecification;
|
|
1688
|
+
/** The resolved simulator UDID the specs run against. */
|
|
1689
|
+
udid: string;
|
|
1690
|
+
}
|
|
1691
|
+
declare function startMobile(options: MobileSpecificationOptions): Promise<MobileHandle>;
|
|
1692
|
+
//#endregion
|
|
1361
1693
|
//#region src/core/specification/website/serve.adapter.d.ts
|
|
1362
1694
|
/** Options for the local server started by `specification.website()`. */
|
|
1363
1695
|
interface ServeOptions {
|
|
@@ -1372,11 +1704,25 @@ interface ServeOptions {
|
|
|
1372
1704
|
}
|
|
1373
1705
|
//#endregion
|
|
1374
1706
|
//#region src/core/specification/website/start-website.d.ts
|
|
1707
|
+
/**
|
|
1708
|
+
* The declared stub backend behind the site under test — started before the
|
|
1709
|
+
* server command, torn down with the runner. Its URL is injected into the
|
|
1710
|
+
* server child's environment under `env`; the contracts each chain declares
|
|
1711
|
+
* via `.intercept(...)` are what it serves.
|
|
1712
|
+
*/
|
|
1713
|
+
interface WebsiteBackendOptions {
|
|
1714
|
+
/** Env var receiving the stub's URL in the server child (e.g. `'API_URL'`). */
|
|
1715
|
+
env: string;
|
|
1716
|
+
/** Fixed port — pins a stable stub URL across runs. Default: a free OS-assigned port. */
|
|
1717
|
+
port?: number;
|
|
1718
|
+
}
|
|
1375
1719
|
/**
|
|
1376
1720
|
* Options for {@link startWebsite | specification.website}. `server` (start
|
|
1377
1721
|
* the site locally) and `url` (target a running site) are mutually
|
|
1378
1722
|
* exclusive BY TYPE — the union makes the invalid combinations
|
|
1379
|
-
* inexpressible rather than runtime-checked.
|
|
1723
|
+
* inexpressible rather than runtime-checked. `backend` requires `server`
|
|
1724
|
+
* mode for the same reason: a deployed site cannot be pointed at a local
|
|
1725
|
+
* stub.
|
|
1380
1726
|
*/
|
|
1381
1727
|
type WebsiteSpecificationOptions = {
|
|
1382
1728
|
/**
|
|
@@ -1391,6 +1737,12 @@ type WebsiteSpecificationOptions = {
|
|
|
1391
1737
|
*/
|
|
1392
1738
|
root?: string;
|
|
1393
1739
|
} & ({
|
|
1740
|
+
/**
|
|
1741
|
+
* Declared stub backend: started BEFORE the server command, its
|
|
1742
|
+
* URL injected into the child env under `backend.env`. Serves the
|
|
1743
|
+
* contracts each chain declares via `.intercept(...)`.
|
|
1744
|
+
*/
|
|
1745
|
+
backend?: WebsiteBackendOptions;
|
|
1394
1746
|
/**
|
|
1395
1747
|
* Start the site locally: a shell command receiving a free port
|
|
1396
1748
|
* as `PORT`, polled on `ready` (default `/`) until it answers.
|
|
@@ -1398,6 +1750,7 @@ type WebsiteSpecificationOptions = {
|
|
|
1398
1750
|
server: ServeOptions;
|
|
1399
1751
|
url?: never;
|
|
1400
1752
|
} | {
|
|
1753
|
+
backend?: never;
|
|
1401
1754
|
server?: never;
|
|
1402
1755
|
/** Target an already-running site (a deployed or preview URL). */
|
|
1403
1756
|
url: string;
|
|
@@ -1419,7 +1772,7 @@ declare function startWebsite(options: WebsiteSpecificationOptions): Promise<Web
|
|
|
1419
1772
|
//#endregion
|
|
1420
1773
|
//#region src/core/specification/shared/specification.d.ts
|
|
1421
1774
|
/**
|
|
1422
|
-
* The
|
|
1775
|
+
* The five specification constructors (CONVENTIONS A2) — created in a
|
|
1423
1776
|
* `*.specification.ts` file under `specs/`, destructured with canonical
|
|
1424
1777
|
* names, and cleaned up via `afterAll(cleanup)` (A1/A3/A4).
|
|
1425
1778
|
*
|
|
@@ -1462,6 +1815,13 @@ declare const specification: {
|
|
|
1462
1815
|
* server, no mode. `.trigger(name)` is the terminal action.
|
|
1463
1816
|
*/
|
|
1464
1817
|
jobs: typeof startJobs;
|
|
1818
|
+
/**
|
|
1819
|
+
* Test a native app on the iOS simulator. `device` names the simulator
|
|
1820
|
+
* (resolved and booted via `simctl`); `app` names the bundle under
|
|
1821
|
+
* test. `.open(deepLink?, scenario?)` relaunches the app fresh, runs
|
|
1822
|
+
* the scenario, and captures the final screen.
|
|
1823
|
+
*/
|
|
1824
|
+
mobile: typeof startMobile;
|
|
1465
1825
|
/**
|
|
1466
1826
|
* Test a deployed or locally-served website. `server` starts the site
|
|
1467
1827
|
* (a shell command receiving `PORT`); `url` targets a running one.
|
|
@@ -1702,20 +2062,38 @@ declare class SqliteHandle implements DatabasePort, ServiceHandle {
|
|
|
1702
2062
|
*/
|
|
1703
2063
|
declare function sqlite(options?: SqliteOptions): SqliteHandle;
|
|
1704
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
|
|
1705
2083
|
//#region src/integrations/anthropic/anthropic.d.ts
|
|
1706
2084
|
interface AnthropicMessagesFilter {
|
|
1707
|
-
model?:
|
|
1708
|
-
system?:
|
|
1709
|
-
user?:
|
|
2085
|
+
model?: TextFilter;
|
|
2086
|
+
system?: TextFilter;
|
|
2087
|
+
user?: TextFilter;
|
|
1710
2088
|
tools?: string[];
|
|
1711
2089
|
}
|
|
1712
|
-
declare function buildReply(data: unknown):
|
|
2090
|
+
declare function buildReply(data: unknown): ContractResponse;
|
|
1713
2091
|
/**
|
|
1714
2092
|
* Anthropic API intercept helpers.
|
|
1715
2093
|
*/
|
|
1716
2094
|
declare const anthropic: {
|
|
1717
2095
|
/**
|
|
1718
|
-
*
|
|
2096
|
+
* Request: match Messages API calls, optionally routed through a
|
|
1719
2097
|
* custom gateway URL. When used with a JSON fixture file, the data is
|
|
1720
2098
|
* returned as-is (no wrapping) because Anthropic fixtures are typically
|
|
1721
2099
|
* already in the Messages API response shape.
|
|
@@ -1723,15 +2101,16 @@ declare const anthropic: {
|
|
|
1723
2101
|
* @example
|
|
1724
2102
|
* anthropic.messages()
|
|
1725
2103
|
* anthropic.messages({ system: /classify/ })
|
|
2104
|
+
* anthropic.messages({ user: buildPrompt() }) // string = EXACT equality
|
|
1726
2105
|
* anthropic.messages({ user: /classify/ }, GATEWAY)
|
|
1727
2106
|
*/
|
|
1728
|
-
messages(filter?: AnthropicMessagesFilter, url?: string):
|
|
2107
|
+
messages(filter?: AnthropicMessagesFilter, url?: string): ContractRequest;
|
|
1729
2108
|
/** Response: wrap data in Anthropic messages format. */
|
|
1730
2109
|
reply: typeof buildReply;
|
|
1731
2110
|
/** Response: return an Anthropic error. */
|
|
1732
|
-
error(status: number, message?: string):
|
|
2111
|
+
error(status: number, message?: string): ContractResponse;
|
|
1733
2112
|
/** Response: simulate a timeout. */
|
|
1734
|
-
timeout():
|
|
2113
|
+
timeout(): ContractResponse;
|
|
1735
2114
|
};
|
|
1736
2115
|
//#endregion
|
|
1737
2116
|
//#region src/core/contracts/http.d.ts
|
|
@@ -1739,7 +2118,7 @@ declare const anthropic: {
|
|
|
1739
2118
|
* Request filters for the generic HTTP provider. Every field is a subset
|
|
1740
2119
|
* constraint — a request matches when all provided fields match.
|
|
1741
2120
|
*/
|
|
1742
|
-
interface
|
|
2121
|
+
interface HttpContractFilter {
|
|
1743
2122
|
/**
|
|
1744
2123
|
* Body constraint. An object is a deep SUBSET match (toMatchObject-style)
|
|
1745
2124
|
* whose leaf values may be `match.*` matchers; a string is a containment
|
|
@@ -1751,58 +2130,78 @@ interface HttpInterceptFilter {
|
|
|
1751
2130
|
/** Query-param subset. string = exact value, RegExp = `test()`. */
|
|
1752
2131
|
query?: Record<string, RegExp | string>;
|
|
1753
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
|
+
}
|
|
1754
2142
|
/**
|
|
1755
|
-
* Generic HTTP
|
|
1756
|
-
*
|
|
1757
|
-
*
|
|
1758
|
-
*
|
|
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).
|
|
1759
2149
|
*
|
|
1760
2150
|
* @example
|
|
1761
|
-
*
|
|
1762
|
-
*
|
|
2151
|
+
* defineContract({ request: http.get('/articles/{{uuid}}'), response: http.json(article) })
|
|
2152
|
+
* defineContract({ request: http.post(URL, { body: { user: 'alice' } }), response: http.empty() })
|
|
1763
2153
|
*/
|
|
1764
2154
|
declare const http: {
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
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;
|
|
1774
2169
|
};
|
|
1775
2170
|
//#endregion
|
|
1776
2171
|
//#region src/integrations/openai/openai.d.ts
|
|
1777
2172
|
interface OpenAIChatFilter {
|
|
1778
|
-
model?:
|
|
1779
|
-
system?:
|
|
1780
|
-
user?:
|
|
2173
|
+
model?: TextFilter;
|
|
2174
|
+
system?: TextFilter;
|
|
2175
|
+
user?: TextFilter;
|
|
1781
2176
|
tools?: string[];
|
|
1782
2177
|
temperature?: number;
|
|
1783
2178
|
}
|
|
1784
2179
|
interface OpenAIResponsesFilter {
|
|
1785
|
-
model?:
|
|
1786
|
-
system?:
|
|
1787
|
-
user?:
|
|
2180
|
+
model?: TextFilter;
|
|
2181
|
+
system?: TextFilter;
|
|
2182
|
+
user?: TextFilter;
|
|
1788
2183
|
tools?: string[];
|
|
1789
2184
|
}
|
|
1790
|
-
declare function buildChatReply(data: unknown):
|
|
2185
|
+
declare function buildChatReply(data: unknown): ContractResponse;
|
|
1791
2186
|
/**
|
|
1792
2187
|
* OpenAI API intercept helpers.
|
|
1793
2188
|
*/
|
|
1794
2189
|
declare const openai: {
|
|
1795
2190
|
/**
|
|
1796
|
-
*
|
|
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(...)`.
|
|
1797
2194
|
*
|
|
1798
2195
|
* @example
|
|
1799
|
-
* openai.chat()
|
|
1800
|
-
* openai.chat({ model: 'gpt-4o' })
|
|
1801
|
-
* 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
|
|
1802
2200
|
*/
|
|
1803
|
-
chat(filter?: OpenAIChatFilter):
|
|
2201
|
+
chat(filter?: OpenAIChatFilter): ContractRequest;
|
|
1804
2202
|
/**
|
|
1805
|
-
*
|
|
2203
|
+
* Request: match Responses API calls (AI SDK v5+) with auto-wrapping.
|
|
2204
|
+
* String filters mean EXACT equality (see {@link openai.chat}).
|
|
1806
2205
|
* When used with a JSON file, the data is automatically wrapped in the
|
|
1807
2206
|
* Responses API envelope.
|
|
1808
2207
|
*
|
|
@@ -1812,7 +2211,7 @@ declare const openai: {
|
|
|
1812
2211
|
* @example
|
|
1813
2212
|
* openai.responses({ user: /Report Ingestion/ }, GATEWAY)
|
|
1814
2213
|
*/
|
|
1815
|
-
responses(filter?: OpenAIResponsesFilter, url?: string):
|
|
2214
|
+
responses(filter?: OpenAIResponsesFilter, url?: string): ContractRequest;
|
|
1816
2215
|
/**
|
|
1817
2216
|
* Response: wrap data in Chat Completions format.
|
|
1818
2217
|
*
|
|
@@ -1821,11 +2220,11 @@ declare const openai: {
|
|
|
1821
2220
|
*/
|
|
1822
2221
|
reply: typeof buildChatReply;
|
|
1823
2222
|
/** Response: return an OpenAI error. */
|
|
1824
|
-
error(status: number, message?: string):
|
|
2223
|
+
error(status: number, message?: string): ContractResponse;
|
|
1825
2224
|
/** Response: return malformed content. */
|
|
1826
|
-
malformed(content: string):
|
|
2225
|
+
malformed(content: string): ContractResponse;
|
|
1827
2226
|
/** Response: simulate a timeout. */
|
|
1828
|
-
timeout():
|
|
2227
|
+
timeout(): ContractResponse;
|
|
1829
2228
|
};
|
|
1830
2229
|
//#endregion
|
|
1831
2230
|
//#region src/vitest/mock-of.d.ts
|
|
@@ -1891,4 +2290,4 @@ declare module 'vitest' {
|
|
|
1891
2290
|
}
|
|
1892
2291
|
}
|
|
1893
2292
|
//#endregion
|
|
1894
|
-
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, DirectoryAccessor, type DockerSpecConfig, type ElementKind, type ElementMatch, type ElementOptions, type ElementRef, type ExecOptions, FetchResult, type FileAccessor, FilesystemAccessor, type HonoApp, HttpResult, type
|
|
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 };
|