@orkestrel/test 0.0.15 → 0.0.17
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 +7 -5
- package/dist/src/browser/index.d.ts +677 -8
- package/dist/src/browser/index.js +686 -1
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/core/index.cjs +99 -16
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +580 -456
- package/dist/src/core/index.d.ts +580 -456
- package/dist/src/core/index.js +98 -17
- package/dist/src/core/index.js.map +1 -1
- package/package.json +5 -5
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the error a refused fixture build raises, named for the row it was building for.
|
|
3
|
+
*
|
|
4
|
+
* @param name - The row's name, which opens the message.
|
|
5
|
+
* @param cause - The value the builder refused with, which becomes the returned error's `cause`.
|
|
6
|
+
* @returns The refusal, unthrown.
|
|
7
|
+
* @remarks {@link executeScenarios} raises this one, and `createHarness` in the browser environment
|
|
8
|
+
* announces its `message` on the row it refused, so the runner and the harness name a refused build
|
|
9
|
+
* with one sentence rather than two spellings of it. The refusal arrives as the `cause` by identity,
|
|
10
|
+
* so its own message and stack survive the naming.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { buildRefusal } from '@orkestrel/test'
|
|
15
|
+
*
|
|
16
|
+
* buildRefusal('closed opens through the summary', new Error('no fixture')).message
|
|
17
|
+
* // 'closed opens through the summary: build refused'
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function buildRefusal(name: string, cause: unknown): Error;
|
|
21
|
+
|
|
1
22
|
/**
|
|
2
23
|
* Builds the error {@link retryUntil} raises when its elapsed-time budget runs out.
|
|
3
24
|
*
|
|
@@ -281,462 +302,565 @@ export declare function executeScenario<TState extends string, TEvent extends st
|
|
|
281
302
|
* @param scenarios - The table to drive, in the order it is written.
|
|
282
303
|
* @param build - The fixture builder, called once per row and awaited when it returns a promise.
|
|
283
304
|
* @returns A promise that resolves after the last row completes.
|
|
284
|
-
* @throws
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
* the row it is building for, which is what lets one table mix fixtures.
|
|
291
|
-
*
|
|
292
|
-
* A refusing builder is named for its row the way a failing phase is, because a table's rows build
|
|
293
|
-
* under one test name too. The refusal itself arrives as the `cause`, by identity, so its own
|
|
294
|
-
* message and stack survive the naming.
|
|
295
|
-
*
|
|
296
|
-
* @example
|
|
297
|
-
* ```ts
|
|
298
|
-
* await executeScenarios(SCENARIOS, () => ({ disclosure: new Disclosure() }))
|
|
299
|
-
* ```
|
|
300
|
-
*/
|
|
301
|
-
export declare function executeScenarios<TState extends string, TEvent extends string, TContext>(scenarios: ReadonlyArray<StateScenario<TState, TEvent, TContext>>, build: (scenario: StateScenario<TState, TEvent, TContext>) => TContext | Promise<TContext>): Promise<void>;
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* Normalizes headers into a frozen plain record.
|
|
305
|
-
*
|
|
306
|
-
* @param init - The platform header initializer to normalize.
|
|
307
|
-
* @returns A frozen record of normalized header names and values.
|
|
308
|
-
* @remarks Normalization follows the host `Headers` implementation, including lowercased names and
|
|
309
|
-
* combined values.
|
|
310
|
-
*/
|
|
311
|
-
export declare function flattenHeaders(init: HeadersSource): Readonly<Record<string, string>>;
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* Covers any value the host `Headers` constructor accepts.
|
|
315
|
-
*
|
|
316
|
-
* @remarks Derived from the host constructor rather than named from a single library, so the type
|
|
317
|
-
* resolves in every project against that project's own `Headers` declaration. The record,
|
|
318
|
-
* entries-array, and `Headers` forms all satisfy it.
|
|
319
|
-
*/
|
|
320
|
-
export declare type HeadersSource = NonNullable<ConstructorParameters<typeof Headers>[0]>;
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* Invokes an unknown method through an explicit unchecked result contract.
|
|
324
|
-
*
|
|
325
|
-
* @typeParam T - The result type claimed by the caller.
|
|
326
|
-
* @param target - The value used as the method's `this` argument.
|
|
327
|
-
* @param method - The unknown method to invoke.
|
|
328
|
-
* @param args - The arguments to pass.
|
|
329
|
-
* @returns The method's result under the caller's claimed type.
|
|
330
|
-
* @throws A `TypeError` when `method` is not callable.
|
|
331
|
-
* @remarks The caller owns the claim that the returned value has type `T`. The contained `any`
|
|
332
|
-
* bridges the unchecked runtime result to that caller-owned claim.
|
|
333
|
-
*/
|
|
334
|
-
export declare function invokeUnchecked<T>(target: unknown, method: unknown, args: readonly unknown[]): T;
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Checks whether a value contains a recorder for every listed event.
|
|
338
|
-
*
|
|
339
|
-
* @typeParam TMap - The source's event names and delivered argument tuples.
|
|
340
|
-
* @typeParam TName - The event names represented in the map.
|
|
341
|
-
* @param value - The value to inspect.
|
|
342
|
-
* @param events - The events the completed map must contain.
|
|
343
|
-
* @returns True if every listed event has a structurally valid recorder; false otherwise.
|
|
344
|
-
* @remarks Per-key tuple precision is the predicate's claim. The factory proves that claim by
|
|
345
|
-
* wiring each recorder to exactly the event where it stores that recorder. A direct caller must
|
|
346
|
-
* establish the same pairing before it relies on the narrowing. This guard takes the listed events
|
|
347
|
-
* through a reference parameter rather than using the canonical single-value guard form.
|
|
348
|
-
*
|
|
349
|
-
* @example
|
|
350
|
-
* ```ts
|
|
351
|
-
* import { createRecorder, isRecorderMapComplete } from '@orkestrel/test'
|
|
352
|
-
*
|
|
353
|
-
* type ReadyEvents = { readonly ready: readonly [name: string, step: number] }
|
|
354
|
-
*
|
|
355
|
-
* const value: unknown = { ready: createRecorder<readonly [name: string, step: number]>() }
|
|
356
|
-
*
|
|
357
|
-
* isRecorderMapComplete<ReadyEvents, 'ready'>(value, ['ready']) // true
|
|
358
|
-
* isRecorderMapComplete<ReadyEvents, 'ready'>({ ready: 1 }, ['ready']) // false
|
|
359
|
-
* ```
|
|
360
|
-
*/
|
|
361
|
-
export declare function isRecorderMapComplete<TMap extends Record<string, readonly unknown[]>, TName extends keyof TMap>(value: unknown, events: readonly TName[]): value is RecorderMap<TMap, TName>;
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* Represents the JSON-safe projection of a type: every member JSON preserves, mapped to itself, and
|
|
365
|
-
* every member it does not, mapped to `never`.
|
|
366
|
-
*
|
|
367
|
-
* @typeParam T - The type to project.
|
|
368
|
-
* @remarks Intersect a parameter with this rather than constraining it to `JSONValue`. A `JSONValue`
|
|
369
|
-
* constraint rejects every `interface`, because TypeScript grants an implicit index signature to a
|
|
370
|
-
* type alias and never to an interface, and interfaces are what this project's public types are. A
|
|
371
|
-
* value whose type survives the projection satisfies the intersection unchanged; one that carries a
|
|
372
|
-
* method, a `Date`, a `Map`, the opaque `object` type, or a symbol-keyed member meets `never` at that
|
|
373
|
-
* member and is rejected there. A member typed `undefined` is rejected the same way, because
|
|
374
|
-
* serialization drops it from an object and rewrites it to `null` in an array, so the returned type
|
|
375
|
-
* would claim a member the copy does not carry. An optional member survives, since its declared type
|
|
376
|
-
* still narrows to what JSON keeps. A member declared `?: X | undefined` and passed an explicit
|
|
377
|
-
* `undefined` is refused; declare it `?: X` and omit the member instead. `unknown` passes through
|
|
378
|
-
* unvetted by the projection. For an `unknown` member, `roundTripJSON` refuses `undefined`,
|
|
379
|
-
* functions, symbols, and non-finite numbers at runtime; JSON otherwise may silently reshape the
|
|
380
|
-
* value, such as a `Date` to a string or a `Map` to `{}`.
|
|
381
|
-
* @example
|
|
382
|
-
* ```ts
|
|
383
|
-
* interface Snapshot {
|
|
384
|
-
* readonly id: string
|
|
385
|
-
* readonly turns: number
|
|
386
|
-
* }
|
|
387
|
-
*
|
|
388
|
-
* // { readonly id: string; readonly turns: number } — every member survives.
|
|
389
|
-
* type Safe = JSONSafe<Snapshot>
|
|
390
|
-
* ```
|
|
391
|
-
*/
|
|
392
|
-
export declare type JSONSafe<T> = unknown extends T ? T : T extends string | number | boolean | null ? T : T extends ReadonlyArray<infer E> ? ReadonlyArray<JSONSafe<E>> : T extends (...args: never[]) => unknown ? never : T extends object ? object extends T ? never : {
|
|
393
|
-
readonly [K in keyof T]: K extends symbol ? never : JSONSafe<T[K]>;
|
|
394
|
-
} : never;
|
|
395
|
-
|
|
396
|
-
/**
|
|
397
|
-
* Reads a property from an unknown object or function.
|
|
398
|
-
*
|
|
399
|
-
* @typeParam T - The property type claimed by the caller.
|
|
400
|
-
* @param target - The unknown value to read.
|
|
401
|
-
* @param key - The property key to read.
|
|
402
|
-
* @returns The property value under the caller's claimed type.
|
|
403
|
-
* @throws A `TypeError` when `target` is neither an object nor a function.
|
|
404
|
-
* @remarks The caller owns the claim that the returned value has type `T`. The contained `any`
|
|
405
|
-
* bridges the unchecked runtime result to that caller-owned claim.
|
|
406
|
-
*/
|
|
407
|
-
export declare function readProperty<T>(target: unknown, key: PropertyKey): T;
|
|
408
|
-
|
|
409
|
-
/**
|
|
410
|
-
* Records every call made to its handler.
|
|
411
|
-
*
|
|
412
|
-
* @typeParam TArgs - The argument tuple the recorded handler accepts.
|
|
413
|
-
*/
|
|
414
|
-
export declare interface RecorderInterface<TArgs extends readonly unknown[]> {
|
|
415
|
-
/** Lists every recorded call, oldest first, each entry the arguments of one call. */
|
|
416
|
-
readonly calls: readonly TArgs[];
|
|
417
|
-
/** Reports how many calls have been recorded. */
|
|
418
|
-
readonly count: number;
|
|
419
|
-
/** Holds the callback to hand to the code under test. */
|
|
420
|
-
readonly handler: (...args: TArgs) => void;
|
|
421
|
-
/**
|
|
422
|
-
* Discards the recorded calls and keeps the recorder usable.
|
|
423
|
-
*
|
|
424
|
-
* @remarks The list is truncated in place, so a `calls` reference taken earlier empties too.
|
|
425
|
-
*/
|
|
426
|
-
clear(): void;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
/**
|
|
430
|
-
* Maps event names to recorders for their delivered argument tuples.
|
|
431
|
-
*
|
|
432
|
-
* @typeParam TMap - The event names and argument tuples the source delivers.
|
|
433
|
-
* @typeParam TName - The event names represented in the map.
|
|
434
|
-
*/
|
|
435
|
-
export declare type RecorderMap<TMap extends Record<string, readonly unknown[]>, TName extends keyof TMap> = {
|
|
436
|
-
readonly [K in TName]: RecorderInterface<TMap[K]>;
|
|
437
|
-
};
|
|
438
|
-
|
|
439
|
-
/**
|
|
440
|
-
* Narrows a value away from `null` and `undefined`, throwing when it is absent.
|
|
441
|
-
*
|
|
442
|
-
* @typeParam T - The required value type.
|
|
443
|
-
* @param value - The value to check.
|
|
444
|
-
* @param message - The error message used when the value is absent. Default: `'Value is required'`.
|
|
445
|
-
* @returns The present value.
|
|
446
|
-
* @throws An `Error` carrying `message` when the value is `null` or `undefined`.
|
|
447
|
-
*/
|
|
448
|
-
export declare function requireValue<T>(value: T | null | undefined, message?: string): T;
|
|
449
|
-
|
|
450
|
-
/**
|
|
451
|
-
* Resolves the parent directory of a calling module, which is the workspace root when called from
|
|
452
|
-
* the conventional `tests/setup.ts` location.
|
|
453
|
-
*
|
|
454
|
-
* @param meta - The calling module metadata.
|
|
455
|
-
* @returns The root URL one directory above the calling file.
|
|
456
|
-
*/
|
|
457
|
-
export declare function resolveRoot(meta: ImportMeta): URL;
|
|
458
|
-
|
|
459
|
-
/** Represents a numbered resource factory with records of every creation and destruction. */
|
|
460
|
-
export declare interface ResourceFactoryInterface {
|
|
461
|
-
/** Records the ids returned by `create`, in order. */
|
|
462
|
-
readonly created: RecorderInterface<readonly [id: number]>;
|
|
463
|
-
/** Records the ids passed to `destroy`, in order. */
|
|
464
|
-
readonly destroyed: RecorderInterface<readonly [id: number]>;
|
|
465
|
-
/**
|
|
466
|
-
* Creates a numbered resource.
|
|
305
|
+
* @throws {@link buildRefusal}'s `Error` reading `<name>: build refused` when the row's builder
|
|
306
|
+
* throws or rejects, or whatever {@link executeScenario} throws for the first row whose phases
|
|
307
|
+
* fail. Either way the run stops at that row and the rows after it never start.
|
|
308
|
+
* @remarks The rows run one after another rather than together: a statechart's rows drive one
|
|
309
|
+
* entity on one page, so a parallel run would have them arranging over each other. `build` receives
|
|
310
|
+
* the row it is building for, which is what lets one table mix fixtures.
|
|
467
311
|
*
|
|
468
|
-
*
|
|
469
|
-
*
|
|
470
|
-
*
|
|
471
|
-
* at `1`.
|
|
472
|
-
*/
|
|
473
|
-
create(): number;
|
|
474
|
-
/**
|
|
475
|
-
* Destroys a numbered resource.
|
|
312
|
+
* A refusing builder is named for its row the way a failing phase is, because a table's rows build
|
|
313
|
+
* under one test name too. `buildRefusal` owns that sentence, so the harness the browser
|
|
314
|
+
* environment publishes announces the same one rather than a second spelling of it.
|
|
476
315
|
*
|
|
477
|
-
* @
|
|
478
|
-
*
|
|
479
|
-
*
|
|
316
|
+
* @example
|
|
317
|
+
* ```ts
|
|
318
|
+
* await executeScenarios(SCENARIOS, () => ({ disclosure: new Disclosure() }))
|
|
319
|
+
* ```
|
|
480
320
|
*/
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
*/
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
*/
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
*/
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
321
|
+
export declare function executeScenarios<TState extends string, TEvent extends string, TContext>(scenarios: ReadonlyArray<StateScenario<TState, TEvent, TContext>>, build: (scenario: StateScenario<TState, TEvent, TContext>) => TContext | Promise<TContext>): Promise<void>;
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Normalizes headers into a frozen plain record.
|
|
325
|
+
*
|
|
326
|
+
* @param init - The platform header initializer to normalize.
|
|
327
|
+
* @returns A frozen record of normalized header names and values.
|
|
328
|
+
* @remarks Normalization follows the host `Headers` implementation, including lowercased names and
|
|
329
|
+
* combined values.
|
|
330
|
+
*/
|
|
331
|
+
export declare function flattenHeaders(init: HeadersSource): Readonly<Record<string, string>>;
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Covers any value the host `Headers` constructor accepts.
|
|
335
|
+
*
|
|
336
|
+
* @remarks Derived from the host constructor rather than named from a single library, so the type
|
|
337
|
+
* resolves in every project against that project's own `Headers` declaration. The record,
|
|
338
|
+
* entries-array, and `Headers` forms all satisfy it.
|
|
339
|
+
*/
|
|
340
|
+
export declare type HeadersSource = NonNullable<ConstructorParameters<typeof Headers>[0]>;
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Invokes an unknown method through an explicit unchecked result contract.
|
|
344
|
+
*
|
|
345
|
+
* @typeParam T - The result type claimed by the caller.
|
|
346
|
+
* @param target - The value used as the method's `this` argument.
|
|
347
|
+
* @param method - The unknown method to invoke.
|
|
348
|
+
* @param args - The arguments to pass.
|
|
349
|
+
* @returns The method's result under the caller's claimed type.
|
|
350
|
+
* @throws A `TypeError` when `method` is not callable.
|
|
351
|
+
* @remarks The caller owns the claim that the returned value has type `T`. The contained `any`
|
|
352
|
+
* bridges the unchecked runtime result to that caller-owned claim.
|
|
353
|
+
*/
|
|
354
|
+
export declare function invokeUnchecked<T>(target: unknown, method: unknown, args: readonly unknown[]): T;
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Checks whether a value contains a recorder for every listed event.
|
|
358
|
+
*
|
|
359
|
+
* @typeParam TMap - The source's event names and delivered argument tuples.
|
|
360
|
+
* @typeParam TName - The event names represented in the map.
|
|
361
|
+
* @param value - The value to inspect.
|
|
362
|
+
* @param events - The events the completed map must contain.
|
|
363
|
+
* @returns True if every listed event has a structurally valid recorder; false otherwise.
|
|
364
|
+
* @remarks Per-key tuple precision is the predicate's claim. The factory proves that claim by
|
|
365
|
+
* wiring each recorder to exactly the event where it stores that recorder. A direct caller must
|
|
366
|
+
* establish the same pairing before it relies on the narrowing. This guard takes the listed events
|
|
367
|
+
* through a reference parameter rather than using the canonical single-value guard form.
|
|
368
|
+
*
|
|
369
|
+
* @example
|
|
370
|
+
* ```ts
|
|
371
|
+
* import { createRecorder, isRecorderMapComplete } from '@orkestrel/test'
|
|
372
|
+
*
|
|
373
|
+
* type ReadyEvents = { readonly ready: readonly [name: string, step: number] }
|
|
374
|
+
*
|
|
375
|
+
* const value: unknown = { ready: createRecorder<readonly [name: string, step: number]>() }
|
|
376
|
+
*
|
|
377
|
+
* isRecorderMapComplete<ReadyEvents, 'ready'>(value, ['ready']) // true
|
|
378
|
+
* isRecorderMapComplete<ReadyEvents, 'ready'>({ ready: 1 }, ['ready']) // false
|
|
379
|
+
* ```
|
|
380
|
+
*/
|
|
381
|
+
export declare function isRecorderMapComplete<TMap extends Record<string, readonly unknown[]>, TName extends keyof TMap>(value: unknown, events: readonly TName[]): value is RecorderMap<TMap, TName>;
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Represents one theme-and-viewport pair in the form a project configuration can serialize.
|
|
385
|
+
*
|
|
386
|
+
* @remarks
|
|
387
|
+
* A capture matrix is declared twice — once in the configuration that registers one test project
|
|
388
|
+
* per variant, and once in the suite that renders them — so this is the shape the two agree on.
|
|
389
|
+
* Every member is data a JSON file can carry, which is what keeps it reachable from a
|
|
390
|
+
* configuration; the browser environment's `CaptureVariant` extends it with the document change a
|
|
391
|
+
* capture applies, which a configuration cannot carry.
|
|
392
|
+
*/
|
|
393
|
+
export declare interface JourneyVariant {
|
|
394
|
+
/** Holds the variant's name, which is the second half of every filename a capture run writes. */
|
|
395
|
+
readonly name: string;
|
|
396
|
+
/** Holds the viewport width in pixels. */
|
|
397
|
+
readonly width: number;
|
|
398
|
+
/** Holds the viewport height in pixels. */
|
|
399
|
+
readonly height: number;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Represents the JSON-safe projection of a type: every member JSON preserves, mapped to itself, and
|
|
404
|
+
* every member it does not, mapped to `never`.
|
|
405
|
+
*
|
|
406
|
+
* @typeParam T - The type to project.
|
|
407
|
+
* @remarks Intersect a parameter with this rather than constraining it to `JSONValue`. A `JSONValue`
|
|
408
|
+
* constraint rejects every `interface`, because TypeScript grants an implicit index signature to a
|
|
409
|
+
* type alias and never to an interface, and interfaces are what this project's public types are. A
|
|
410
|
+
* value whose type survives the projection satisfies the intersection unchanged; one that carries a
|
|
411
|
+
* method, a `Date`, a `Map`, the opaque `object` type, or a symbol-keyed member meets `never` at that
|
|
412
|
+
* member and is rejected there. A member typed `undefined` is rejected the same way, because
|
|
413
|
+
* serialization drops it from an object and rewrites it to `null` in an array, so the returned type
|
|
414
|
+
* would claim a member the copy does not carry. An optional member survives, since its declared type
|
|
415
|
+
* still narrows to what JSON keeps. A member declared `?: X | undefined` and passed an explicit
|
|
416
|
+
* `undefined` is refused; declare it `?: X` and omit the member instead. `unknown` passes through
|
|
417
|
+
* unvetted by the projection. For an `unknown` member, `roundTripJSON` refuses `undefined`,
|
|
418
|
+
* functions, symbols, and non-finite numbers at runtime; JSON otherwise may silently reshape the
|
|
419
|
+
* value, such as a `Date` to a string or a `Map` to `{}`.
|
|
420
|
+
* @example
|
|
421
|
+
* ```ts
|
|
422
|
+
* interface Snapshot {
|
|
423
|
+
* readonly id: string
|
|
424
|
+
* readonly turns: number
|
|
425
|
+
* }
|
|
426
|
+
*
|
|
427
|
+
* // { readonly id: string; readonly turns: number } — every member survives.
|
|
428
|
+
* type Safe = JSONSafe<Snapshot>
|
|
429
|
+
* ```
|
|
430
|
+
*/
|
|
431
|
+
export declare type JSONSafe<T> = unknown extends T ? T : T extends string | number | boolean | null ? T : T extends ReadonlyArray<infer E> ? ReadonlyArray<JSONSafe<E>> : T extends (...args: never[]) => unknown ? never : T extends object ? object extends T ? never : {
|
|
432
|
+
readonly [K in keyof T]: K extends symbol ? never : JSONSafe<T[K]>;
|
|
433
|
+
} : never;
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Reads a property from an unknown object or function.
|
|
437
|
+
*
|
|
438
|
+
* @typeParam T - The property type claimed by the caller.
|
|
439
|
+
* @param target - The unknown value to read.
|
|
440
|
+
* @param key - The property key to read.
|
|
441
|
+
* @returns The property value under the caller's claimed type.
|
|
442
|
+
* @throws A `TypeError` when `target` is neither an object nor a function.
|
|
443
|
+
* @remarks The caller owns the claim that the returned value has type `T`. The contained `any`
|
|
444
|
+
* bridges the unchecked runtime result to that caller-owned claim.
|
|
445
|
+
*/
|
|
446
|
+
export declare function readProperty<T>(target: unknown, key: PropertyKey): T;
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Records every call made to its handler.
|
|
450
|
+
*
|
|
451
|
+
* @typeParam TArgs - The argument tuple the recorded handler accepts.
|
|
452
|
+
*/
|
|
453
|
+
export declare interface RecorderInterface<TArgs extends readonly unknown[]> {
|
|
454
|
+
/** Lists every recorded call, oldest first, each entry the arguments of one call. */
|
|
455
|
+
readonly calls: readonly TArgs[];
|
|
456
|
+
/** Reports how many calls have been recorded. */
|
|
457
|
+
readonly count: number;
|
|
458
|
+
/** Holds the callback to hand to the code under test. */
|
|
459
|
+
readonly handler: (...args: TArgs) => void;
|
|
460
|
+
/**
|
|
461
|
+
* Discards the recorded calls and keeps the recorder usable.
|
|
462
|
+
*
|
|
463
|
+
* @remarks The list is truncated in place, so a `calls` reference taken earlier empties too.
|
|
464
|
+
*/
|
|
465
|
+
clear(): void;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Maps event names to recorders for their delivered argument tuples.
|
|
470
|
+
*
|
|
471
|
+
* @typeParam TMap - The event names and argument tuples the source delivers.
|
|
472
|
+
* @typeParam TName - The event names represented in the map.
|
|
473
|
+
*/
|
|
474
|
+
export declare type RecorderMap<TMap extends Record<string, readonly unknown[]>, TName extends keyof TMap> = {
|
|
475
|
+
readonly [K in TName]: RecorderInterface<TMap[K]>;
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Narrows a value away from `null` and `undefined`, throwing when it is absent.
|
|
480
|
+
*
|
|
481
|
+
* @typeParam T - The required value type.
|
|
482
|
+
* @param value - The value to check.
|
|
483
|
+
* @param message - The error message used when the value is absent. Default: `'Value is required'`.
|
|
484
|
+
* @returns The present value.
|
|
485
|
+
* @throws An `Error` carrying `message` when the value is `null` or `undefined`.
|
|
486
|
+
*/
|
|
487
|
+
export declare function requireValue<T>(value: T | null | undefined, message?: string): T;
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Resolves the parent directory of a calling module, which is the workspace root when called from
|
|
491
|
+
* the conventional `tests/setup.ts` location.
|
|
492
|
+
*
|
|
493
|
+
* @param meta - The calling module metadata.
|
|
494
|
+
* @returns The root URL one directory above the calling file.
|
|
495
|
+
*/
|
|
496
|
+
export declare function resolveRoot(meta: ImportMeta): URL;
|
|
497
|
+
|
|
498
|
+
/** Represents a numbered resource factory with records of every creation and destruction. */
|
|
499
|
+
export declare interface ResourceFactoryInterface {
|
|
500
|
+
/** Records the ids returned by `create`, in order. */
|
|
501
|
+
readonly created: RecorderInterface<readonly [id: number]>;
|
|
502
|
+
/** Records the ids passed to `destroy`, in order. */
|
|
503
|
+
readonly destroyed: RecorderInterface<readonly [id: number]>;
|
|
504
|
+
/**
|
|
505
|
+
* Creates a numbered resource.
|
|
506
|
+
*
|
|
507
|
+
* @returns The next monotonically increasing id.
|
|
508
|
+
* @remarks The id is the creation record's length plus one, so it counts allocations rather than
|
|
509
|
+
* live resources: a destroyed id is never reissued, and clearing `created` restarts the numbering
|
|
510
|
+
* at `1`.
|
|
511
|
+
*/
|
|
512
|
+
create(): number;
|
|
513
|
+
/**
|
|
514
|
+
* Destroys a numbered resource.
|
|
515
|
+
*
|
|
516
|
+
* @param id - The resource id to destroy.
|
|
517
|
+
* @remarks It records the id and nothing else: it frees nothing, refuses nothing, and accepts an
|
|
518
|
+
* id that was never created, so a suite asserts on the record rather than on a refusal.
|
|
519
|
+
*/
|
|
520
|
+
destroy(id: number): void;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/** Configures a bounded retry, adding an optional producer-call limit to a bounded wait's bounds. */
|
|
524
|
+
export declare interface RetryOptions extends WaitOptions {
|
|
525
|
+
/** Caps the number of producer calls. When omitted, only the time budget bounds the retry. */
|
|
526
|
+
readonly attempts?: number;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Repeats a producer until one produced value satisfies a predicate.
|
|
531
|
+
*
|
|
532
|
+
* @typeParam T - The produced value type.
|
|
533
|
+
* @param description - The operation described in an exhaustion error.
|
|
534
|
+
* @param produce - The synchronous or asynchronous operation to repeat.
|
|
535
|
+
* @param satisfied - The predicate that accepts a produced value.
|
|
536
|
+
* @param options - The time, attempt, and abort bounds.
|
|
537
|
+
* @returns The first produced value the predicate accepts.
|
|
538
|
+
* @throws The predicate's thrown value, the abort reason, or an `Error` when a bound is invalid or
|
|
539
|
+
* the retry exhausts its budget or attempts.
|
|
540
|
+
* @remarks A producer throw counts as an unsatisfied attempt. The last producer error becomes the
|
|
541
|
+
* exhaustion error's `cause`. Default budget: `1000` milliseconds. Default interval: `10`
|
|
542
|
+
* milliseconds.
|
|
543
|
+
*/
|
|
544
|
+
export declare function retryUntil<T>(description: string, produce: () => T | Promise<T>, satisfied: (value: T) => boolean, options?: RetryOptions): Promise<T>;
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Copies a JSON value through serialization and parsing.
|
|
548
|
+
*
|
|
549
|
+
* @typeParam T - The copied value's type, which the copy keeps.
|
|
550
|
+
* @param value - The value to copy, bounded by its own `JSONSafe` projection.
|
|
551
|
+
* @returns The parsed JSON copy.
|
|
552
|
+
* @remarks Non-finite numbers throw because JSON would replace them with `null`. Negative zero is
|
|
553
|
+
* normalized to zero by JSON serialization. The bound intersects `JSONSafe<T>` rather than
|
|
554
|
+
* constraining `T` to `JSONValue`, so an interface-typed value round-trips.
|
|
555
|
+
*/
|
|
556
|
+
export declare function roundTripJSON<T>(value: T & JSONSafe<T>): T;
|
|
557
|
+
|
|
558
|
+
/** Holds a real abort signal and controller instrumented with its live abort-listener tally. */
|
|
559
|
+
export declare interface SignalInterface {
|
|
560
|
+
/** Holds the controller that owns the signal. */
|
|
561
|
+
readonly controller: AbortController;
|
|
562
|
+
/** Holds the signal to hand to the code under test. */
|
|
563
|
+
readonly signal: AbortSignal;
|
|
564
|
+
/** Reports the live abort-listener tally. */
|
|
565
|
+
readonly count: number;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Represents one abort listener an instrumented signal installed, as its tally holds it.
|
|
570
|
+
*
|
|
571
|
+
* @remarks The members are the listener the caller supplied, the listener installed in its place,
|
|
572
|
+
* the capture flag the pair was registered under, and the controller that removes the scope
|
|
573
|
+
* subscription installed beside it, which is `undefined` where no other signal scopes the
|
|
574
|
+
* registration.
|
|
575
|
+
*/
|
|
576
|
+
export declare type SignalRegistration = readonly [
|
|
577
|
+
listener: EventListener | EventListenerObject,
|
|
578
|
+
installed: EventListener | EventListenerObject,
|
|
579
|
+
capture: boolean,
|
|
580
|
+
cleanup: AbortController | undefined
|
|
581
|
+
];
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Names the attributes a statechart harness publishes, keyed by the fact each one carries.
|
|
585
|
+
*
|
|
586
|
+
* @remarks
|
|
587
|
+
* A harness renders its own table and a gate outside the page polls the rendered markup, so these
|
|
588
|
+
* names are the whole contract between the two. `status`, `passed`, `failed`, and `total` belong on
|
|
589
|
+
* the harness root, because a gate finds the harness by `status` and reads the tally from the same
|
|
590
|
+
* element. `scenario` and `result` belong on each row, so a failing row is found by `result` and
|
|
591
|
+
* named by `scenario`. `state` belongs on the element rendering the entity's current state.
|
|
592
|
+
*
|
|
593
|
+
* The values are the attribute names themselves, so a harness writes `setAttribute` against this map
|
|
594
|
+
* and a gate writes `querySelector` against it, and neither spells a `data-statechart-*` string of
|
|
595
|
+
* its own. `createHarness` in the browser environment is the harness this package publishes, and it
|
|
596
|
+
* writes every one of these names from here.
|
|
597
|
+
*
|
|
598
|
+
* @example
|
|
599
|
+
* ```ts
|
|
600
|
+
* harness.getAttribute(STATECHART_ATTRIBUTES.status) // 'passed'
|
|
601
|
+
* ```
|
|
602
|
+
*/
|
|
603
|
+
export declare const STATECHART_ATTRIBUTES: Readonly<{
|
|
604
|
+
status: "data-statechart-status";
|
|
605
|
+
passed: "data-statechart-passed";
|
|
606
|
+
failed: "data-statechart-failed";
|
|
607
|
+
total: "data-statechart-total";
|
|
608
|
+
scenario: "data-statechart-scenario";
|
|
609
|
+
result: "data-statechart-result";
|
|
610
|
+
state: "data-statechart-state";
|
|
611
|
+
}>;
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Lists every value a statechart harness reports through its `status` attribute.
|
|
615
|
+
*
|
|
616
|
+
* @remarks
|
|
617
|
+
* `pending` is what a harness carries while its inventory is incomplete: written at construction
|
|
618
|
+
* and replaced as soon as every declared row has rendered its `scenario` element and the root
|
|
619
|
+
* carries the row count. A gate that finds it has found a harness whose rows never mounted. `idle`
|
|
620
|
+
* is a mounted harness standing ready, its tally at zero and nothing running. `running` is a run in
|
|
621
|
+
* flight. `passed` and `failed` are the two terminal readings, so a gate waits for membership in
|
|
622
|
+
* that pair rather than for a fixed duration. An exceptional exit is terminal too: a harness whose
|
|
623
|
+
* `state` reader throws writes `failed` and then rejects the run, so the gate reads a terminal pair
|
|
624
|
+
* while the suite reads the throw.
|
|
625
|
+
*
|
|
626
|
+
* The tuple's order is the order a run passes through, and `StatechartStatus` is the same set as a
|
|
627
|
+
* named union, so a harness and its gate share one vocabulary whichever form each of them needs.
|
|
628
|
+
*
|
|
629
|
+
* @example
|
|
630
|
+
* ```ts
|
|
631
|
+
* const terminal = new Set<StatechartStatus>(['passed', 'failed'])
|
|
632
|
+
* terminal.has('running') // false
|
|
633
|
+
* ```
|
|
634
|
+
*/
|
|
635
|
+
export declare const STATECHART_STATUSES: readonly ["pending", "idle", "running", "passed", "failed"];
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Names the run state a statechart harness publishes through its status attribute.
|
|
639
|
+
*
|
|
640
|
+
* @remarks
|
|
641
|
+
* Each arm is observable from the harness root alone, which is what lets a gate outside the page
|
|
642
|
+
* decide from the markup rather than from anything the harness tells it. `pending` is a harness
|
|
643
|
+
* whose inventory is incomplete: it is written at construction and replaced as soon as every
|
|
644
|
+
* declared row has rendered and the root carries the row count, so a gate that reads it has found a
|
|
645
|
+
* harness whose rows never mounted. `idle` is a mounted harness standing ready with nothing
|
|
646
|
+
* running. `running` is a run in flight. `passed` and `failed` are the two terminal readings, so a
|
|
647
|
+
* gate waits for membership in that pair rather than for a fixed duration. An exceptional exit is
|
|
648
|
+
* terminal too: a harness whose `state` reader throws writes `failed` and then rejects the run, so
|
|
649
|
+
* the gate reads a terminal pair while the suite reads the throw.
|
|
650
|
+
*
|
|
651
|
+
* `STATECHART_STATUSES` lists the same arms in the order a run passes through them, so a gate that
|
|
652
|
+
* needs the values at runtime reads them from there rather than respelling the union.
|
|
653
|
+
*/
|
|
654
|
+
export declare type StatechartStatus = 'pending' | 'idle' | 'running' | 'passed' | 'failed';
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Drives one {@link StateTransition} through the three phases that prove it.
|
|
658
|
+
*
|
|
659
|
+
* @typeParam TState - The states the entity moves between, as a string-literal union.
|
|
660
|
+
* @typeParam TEvent - The events the entity accepts, as a string-literal union.
|
|
661
|
+
* @typeParam TContext - The fixture the three phases drive.
|
|
662
|
+
* @remarks Each phase receives the context and the part of the transition it is responsible for, so
|
|
663
|
+
* a phase reads its subject from its own parameters rather than from the row it belongs to. A phase
|
|
664
|
+
* may be synchronous or asynchronous, and `executeScenario` awaits each one before starting the
|
|
665
|
+
* next.
|
|
666
|
+
*/
|
|
667
|
+
export declare interface StateScenario<TState extends string, TEvent extends string, TContext> {
|
|
668
|
+
/** Holds the row this scenario drives. */
|
|
669
|
+
readonly transition: StateTransition<TState, TEvent>;
|
|
670
|
+
/**
|
|
671
|
+
* Puts the entity into the transition's `from` state.
|
|
672
|
+
*
|
|
673
|
+
* @param context - The fixture this row drives.
|
|
674
|
+
* @param state - The transition's `from` state.
|
|
675
|
+
*/
|
|
676
|
+
arrange(context: TContext, state: TState): Promise<void> | void;
|
|
677
|
+
/**
|
|
678
|
+
* Applies the transition's event to the arranged entity.
|
|
679
|
+
*
|
|
680
|
+
* @param context - The fixture this row drives.
|
|
681
|
+
* @param event - The transition's event.
|
|
682
|
+
*/
|
|
683
|
+
act(context: TContext, event: TEvent): Promise<void> | void;
|
|
684
|
+
/**
|
|
685
|
+
* Checks that the entity reached the transition's `to` state.
|
|
686
|
+
*
|
|
687
|
+
* @param context - The fixture this row drives.
|
|
688
|
+
* @param state - The transition's `to` state.
|
|
689
|
+
* @remarks Whatever it throws is renamed with the row's name and rethrown.
|
|
690
|
+
*/
|
|
691
|
+
assert(context: TContext, state: TState): Promise<void> | void;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Represents one row of a statechart table: the entity's state before an event, the event, and the
|
|
696
|
+
* state that event must leave it in.
|
|
697
|
+
*
|
|
698
|
+
* @typeParam TState - The states the entity moves between, as a string-literal union.
|
|
699
|
+
* @typeParam TEvent - The events the entity accepts, as a string-literal union.
|
|
700
|
+
* @remarks The two unions are the entity's own vocabulary, so a table naming a state or an event the
|
|
701
|
+
* entity does not have fails to typecheck rather than failing at runtime.
|
|
702
|
+
*/
|
|
703
|
+
export declare interface StateTransition<TState extends string, TEvent extends string> {
|
|
704
|
+
/** Holds the row's name, which is prepended to the message of whatever the row throws. */
|
|
705
|
+
readonly name: string;
|
|
706
|
+
/** Holds the state the row arranges before it acts. */
|
|
707
|
+
readonly from: TState;
|
|
708
|
+
/** Holds the event the row applies to the arranged entity. */
|
|
709
|
+
readonly event: TEvent;
|
|
710
|
+
/** Holds the state the row asserts the entity reached. */
|
|
711
|
+
readonly to: TState;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/** Represents the work one teardown entry performs when the list is destroyed. */
|
|
715
|
+
export declare type TeardownHandler = () => void | Promise<void>;
|
|
716
|
+
|
|
717
|
+
/** Represents the cleanup a test adds as it goes and runs once, newest first, when it is done. */
|
|
718
|
+
export declare interface TeardownInterface {
|
|
719
|
+
/** Reports how many handlers are registered. */
|
|
720
|
+
readonly count: number;
|
|
721
|
+
/**
|
|
722
|
+
* Registers a handler to run when the list is destroyed.
|
|
723
|
+
*
|
|
724
|
+
* @param handler - The work to perform.
|
|
725
|
+
* @remarks Registration order is what `destroy` reverses, so the newest registration is undone
|
|
726
|
+
* first.
|
|
727
|
+
*/
|
|
728
|
+
add(handler: TeardownHandler): void;
|
|
729
|
+
/**
|
|
730
|
+
* Runs every registered handler in reverse registration order, awaiting each in turn, and empties
|
|
731
|
+
* the list.
|
|
732
|
+
*
|
|
733
|
+
* @throws The value the failed handler threw, by identity, when exactly one handler failed. An
|
|
734
|
+
* `AggregateError` carrying every thrown value in run order, when several did.
|
|
735
|
+
* @remarks Every handler runs, including after an earlier one throws or rejects. A handler
|
|
736
|
+
* registered while the run is in progress stays registered for the next call rather than joining
|
|
737
|
+
* this one. The snapshot it ran is discarded, so a repeated call runs nothing that already ran.
|
|
738
|
+
*/
|
|
739
|
+
destroy(): Promise<void>;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* Configures a bounded wait over a reading of text.
|
|
744
|
+
*
|
|
745
|
+
* @remarks
|
|
746
|
+
* The two members are the arrival a wait is for and the departure it must see first. A screen that
|
|
747
|
+
* replaces one sentence with another passes through a moment carrying both, so a wait that names
|
|
748
|
+
* only the arrival can resolve on the frame the old sentence is still painted in. Name the
|
|
749
|
+
* replaced sentence in `absent` and the wait resolves on the reading that carries one and not the
|
|
750
|
+
* other.
|
|
751
|
+
*/
|
|
752
|
+
export declare interface TextWaitOptions extends WaitOptions {
|
|
753
|
+
/** Determines whether the reading must equal the text rather than contain it. */
|
|
754
|
+
readonly exact?: boolean;
|
|
755
|
+
/** Holds a sentence the reading must no longer carry when the wait resolves. */
|
|
756
|
+
readonly absent?: string;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* Waits until an abort signal is aborted.
|
|
761
|
+
*
|
|
762
|
+
* @param signal - The signal to observe.
|
|
763
|
+
* @returns A promise that resolves when the signal is aborted.
|
|
764
|
+
* @remarks An already-aborted signal resolves immediately. Otherwise the wait parks on a one-shot
|
|
765
|
+
* abort listener without a timer or polling.
|
|
766
|
+
*/
|
|
767
|
+
export declare function waitForAbort(signal: AbortSignal): Promise<void>;
|
|
768
|
+
|
|
769
|
+
/**
|
|
770
|
+
* Waits until a condition holds within an elapsed-time budget.
|
|
771
|
+
*
|
|
772
|
+
* @param description - The condition described in a timeout error.
|
|
773
|
+
* @param condition - The synchronous or asynchronous condition to read.
|
|
774
|
+
* @param options - The time bounds and abort signal.
|
|
775
|
+
* @returns A promise that resolves when the condition first returns `true`.
|
|
776
|
+
* @throws The condition's thrown value, the abort reason, or an `Error` when a bound is invalid or
|
|
777
|
+
* the condition does not hold within the budget.
|
|
778
|
+
* @remarks The first read is immediate. Default budget: `1000` milliseconds. Default interval: `10`
|
|
779
|
+
* milliseconds.
|
|
780
|
+
*/
|
|
781
|
+
export declare function waitForCondition(description: string, condition: () => boolean | Promise<boolean>, options?: WaitOptions): Promise<void>;
|
|
782
|
+
|
|
783
|
+
/**
|
|
784
|
+
* Waits for a host timer to elapse.
|
|
785
|
+
*
|
|
786
|
+
* @param ms - The delay in milliseconds. Default: `0`.
|
|
787
|
+
* @returns A promise that resolves after the timer fires.
|
|
788
|
+
*/
|
|
789
|
+
export declare function waitForDelay(ms?: number): Promise<void>;
|
|
790
|
+
|
|
791
|
+
/**
|
|
792
|
+
* Waits for the first delivery from an event subscription.
|
|
793
|
+
*
|
|
794
|
+
* @typeParam TArgs - The delivered argument tuple.
|
|
795
|
+
* @param subscribe - The function that installs the event listener and may return its cleanup.
|
|
796
|
+
* @param description - The event described in a timeout error.
|
|
797
|
+
* @param options - The time bounds and abort signal.
|
|
798
|
+
* @returns The first delivered argument tuple.
|
|
799
|
+
* @throws The subscription's thrown value, the abort reason, or an `Error` when a bound is invalid
|
|
800
|
+
* or the event is not delivered within the budget.
|
|
801
|
+
* @remarks Default budget: `1000` milliseconds. The interval is validated for consistency with the
|
|
802
|
+
* wait family but is not used because this helper parks on the event.
|
|
803
|
+
*/
|
|
804
|
+
export declare function waitForEvent<TArgs extends readonly unknown[]>(subscribe: EventSubscriber<TArgs>, description: string, options?: WaitOptions): Promise<TArgs>;
|
|
805
|
+
|
|
806
|
+
/**
|
|
807
|
+
* Waits until a reading of text carries an expected sentence.
|
|
808
|
+
*
|
|
809
|
+
* @param description - The wait described in a timeout error.
|
|
810
|
+
* @param read - The synchronous reading to take, such as the text of one named region.
|
|
811
|
+
* @param text - The sentence the reading must carry.
|
|
812
|
+
* @param options - The time bounds, the abort signal, the exactness switch, and the departure.
|
|
813
|
+
* @returns The first reading that satisfies the expectation.
|
|
814
|
+
* @throws The reader's thrown value, the abort reason, or an `Error` when `text` or `absent` is
|
|
815
|
+
* empty, `text` carries `absent`, a bound is invalid, or the expectation is not met within the
|
|
816
|
+
* budget.
|
|
817
|
+
* @remarks
|
|
818
|
+
* The reading is a parameter rather than a target this resolves, so the same wait serves a whole
|
|
819
|
+
* page, one named region, and a value a host-independent test computes. Scope it as narrowly as the
|
|
820
|
+
* claim: a wait over the whole page resolves on the sentence wherever it lands.
|
|
821
|
+
*
|
|
822
|
+
* {@link waitForCondition} owns the poll, so the bounds, the timeout voice, and the abort reason are
|
|
823
|
+
* that helper's, and a reader that throws stops the wait rather than counting as a reading that did
|
|
824
|
+
* not satisfy it. Default budget: `1000` milliseconds. Default interval: `10` milliseconds.
|
|
825
|
+
*
|
|
826
|
+
* An empty expectation is refused rather than satisfied by the first reading, because every string
|
|
827
|
+
* contains the empty string and every reading equals it only when the screen is blank.
|
|
828
|
+
*
|
|
829
|
+
* A departure the expectation itself carries is refused the same way, before any reading. A reading
|
|
830
|
+
* that satisfies the arrival carries the departure too — under `exact` it equals `text` and without
|
|
831
|
+
* it contains `text` — so no reading can ever satisfy the poll and the wait would spend its whole
|
|
832
|
+
* budget on a contradiction in the call.
|
|
833
|
+
*
|
|
834
|
+
* @example
|
|
835
|
+
* ```ts
|
|
836
|
+
* import { waitForText } from '@orkestrel/test'
|
|
837
|
+
*
|
|
838
|
+
* await waitForText('the ledger arrives', () => panel.innerText, 'Two entries')
|
|
839
|
+
*
|
|
840
|
+
* // Throws Error: Text expectation must not be empty
|
|
841
|
+
* await waitForText('anything', () => panel.innerText, '')
|
|
842
|
+
*
|
|
843
|
+
* // Throws Error: Text departure must not appear in the text expectation
|
|
844
|
+
* await waitForText('anything', () => panel.innerText, 'Two entries', { absent: 'entries' })
|
|
845
|
+
* ```
|
|
846
|
+
*/
|
|
847
|
+
export declare function waitForText(description: string, read: () => string, text: string, options?: TextWaitOptions): Promise<string>;
|
|
848
|
+
|
|
849
|
+
/**
|
|
850
|
+
* Configures a bounded asynchronous wait with an elapsed-time limit, a delay between readings, and
|
|
851
|
+
* an abort signal.
|
|
852
|
+
*
|
|
853
|
+
* @remarks
|
|
854
|
+
* A default belongs to the function that reads these bounds rather than to the shape, because the
|
|
855
|
+
* consumers do not agree on one. Each states its own numbers in its `@remarks`.
|
|
856
|
+
*/
|
|
857
|
+
export declare interface WaitOptions {
|
|
858
|
+
/** Holds the elapsed-time limit in milliseconds. */
|
|
859
|
+
readonly budget?: number;
|
|
860
|
+
/** Holds the delay between readings in milliseconds. */
|
|
861
|
+
readonly interval?: number;
|
|
862
|
+
/** Holds the signal that aborts the wait. */
|
|
863
|
+
readonly signal?: AbortSignal;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
export { }
|