@ripplo/testing 0.3.8 → 0.3.10
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/dist/actions.d.ts +20 -0
- package/dist/assert.d.ts +6 -0
- package/dist/assert.js +7 -0
- package/dist/{builder-D-i_ueN3.d.ts → builder-CkyzxH7O.d.ts} +66 -2
- package/dist/compiler.d.ts +1 -1
- package/dist/control.d.ts +11 -0
- package/dist/elysia.d.ts +2 -2
- package/dist/{engine-BMfNkIKC.d.ts → engine-CRq3Az6b.d.ts} +1 -1
- package/dist/express.d.ts +2 -2
- package/dist/fastify.d.ts +2 -2
- package/dist/hono.d.ts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/koa.d.ts +2 -2
- package/dist/locators.d.ts +10 -0
- package/dist/lockfile.d.ts +1 -1
- package/dist/nestjs.d.ts +2 -2
- package/dist/nextjs.d.ts +2 -2
- package/package.json +1 -1
package/dist/actions.d.ts
CHANGED
|
@@ -191,6 +191,11 @@ interface HandleDialogOptions {
|
|
|
191
191
|
readonly promptText: string | undefined;
|
|
192
192
|
readonly uiOnly?: boolean;
|
|
193
193
|
}
|
|
194
|
+
/**
|
|
195
|
+
* Respond to a native browser dialog (`alert`, `confirm`, `prompt`). Set
|
|
196
|
+
* `uiOnly: true` only when the dialog has no backend side effect — if it
|
|
197
|
+
* triggers a mutation, wire an observer and keep `uiOnly` off.
|
|
198
|
+
*/
|
|
194
199
|
declare function handleDialog({ action, promptText, uiOnly }: HandleDialogOptions): UnlabeledStep<{
|
|
195
200
|
action: "accept" | "dismiss";
|
|
196
201
|
promptText: string | undefined;
|
|
@@ -202,6 +207,12 @@ interface ClipboardOptions {
|
|
|
202
207
|
readonly target: Variable<string> | undefined;
|
|
203
208
|
readonly value: StringOrVariable | undefined;
|
|
204
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* Read from or write to the browser clipboard. Use when a flow depends on
|
|
212
|
+
* copy/paste (share links, invite tokens) — pair `write` to seed the
|
|
213
|
+
* clipboard before a paste action, or `read` into a `variable()` to assert
|
|
214
|
+
* what the app copied.
|
|
215
|
+
*/
|
|
205
216
|
declare function clipboard({ action, target, value }: ClipboardOptions): UnlabeledStep<{
|
|
206
217
|
action: "read" | "write";
|
|
207
218
|
type: "clipboard";
|
|
@@ -212,6 +223,10 @@ interface SetPermissionOptions {
|
|
|
212
223
|
readonly permission: string;
|
|
213
224
|
readonly state: "granted" | "prompt";
|
|
214
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* Pre-answer a browser permission prompt (geolocation, camera, notifications,
|
|
228
|
+
* clipboard-read, etc.) so the test doesn't stall on the native dialog.
|
|
229
|
+
*/
|
|
215
230
|
declare function setPermission({ permission, state }: SetPermissionOptions): UnlabeledStep<{
|
|
216
231
|
permission: string;
|
|
217
232
|
state: "granted" | "prompt";
|
|
@@ -221,6 +236,11 @@ interface SetViewportOptions {
|
|
|
221
236
|
readonly height: number;
|
|
222
237
|
readonly width: number;
|
|
223
238
|
}
|
|
239
|
+
/**
|
|
240
|
+
* Resize the browser viewport mid-test. Use to cover responsive breakpoints
|
|
241
|
+
* (mobile nav, collapsed sidebars) within the same flow rather than
|
|
242
|
+
* duplicating the test per size.
|
|
243
|
+
*/
|
|
224
244
|
declare function setViewport({ height, width }: SetViewportOptions): UnlabeledStep<{
|
|
225
245
|
height: number;
|
|
226
246
|
type: "setViewport";
|
package/dist/assert.d.ts
CHANGED
|
@@ -67,6 +67,12 @@ declare const assert: {
|
|
|
67
67
|
operator: "equals";
|
|
68
68
|
type: "assertAttribute";
|
|
69
69
|
}>;
|
|
70
|
+
/**
|
|
71
|
+
* Verify a backend side effect by polling an observer. The server-side
|
|
72
|
+
* observer impl returns `ctx.retry(reason)` for transient states (keep
|
|
73
|
+
* polling) and `ctx.fail(reason)` only for invariant violations (stop
|
|
74
|
+
* early). The observer's `.budget()` governs poll interval and timeout.
|
|
75
|
+
*/
|
|
70
76
|
backend<THandle extends ObserverHandle>(observer: THandle, params: ObserverInput<THandle> & Record<string, string>): UnlabeledStep<{
|
|
71
77
|
budget: ObserverBudgetTier;
|
|
72
78
|
observer: string;
|
package/dist/assert.js
CHANGED
|
@@ -37,6 +37,13 @@ var assert = {
|
|
|
37
37
|
type: "assertAttribute"
|
|
38
38
|
});
|
|
39
39
|
},
|
|
40
|
+
// eslint-disable-next-line no-comments/disallowComments
|
|
41
|
+
/**
|
|
42
|
+
* Verify a backend side effect by polling an observer. The server-side
|
|
43
|
+
* observer impl returns `ctx.retry(reason)` for transient states (keep
|
|
44
|
+
* polling) and `ctx.fail(reason)` only for invariant violations (stop
|
|
45
|
+
* early). The observer's `.budget()` governs poll interval and timeout.
|
|
46
|
+
*/
|
|
40
47
|
backend(observer, params) {
|
|
41
48
|
return createStep({
|
|
42
49
|
budget: readObserverBudget(observer),
|
|
@@ -6,6 +6,12 @@ interface ObserverNeedsDescription {
|
|
|
6
6
|
readonly description: (text: string) => ObserverNeedsBudget;
|
|
7
7
|
}
|
|
8
8
|
interface ObserverNeedsBudget {
|
|
9
|
+
/**
|
|
10
|
+
* Polling envelope: interval + total timeout the runner uses when calling
|
|
11
|
+
* `assert.backend()`. Pick by where the side effect lands — fast for
|
|
12
|
+
* same-request DB reads, slow for job-queue settle, async for
|
|
13
|
+
* webhook/email delivery. Too tight = flaky; too loose = slow suite.
|
|
14
|
+
*/
|
|
9
15
|
readonly budget: (tier: ObserverBudget) => ObserverNeedsInput;
|
|
10
16
|
}
|
|
11
17
|
interface ObserverNeedsInput {
|
|
@@ -15,6 +21,11 @@ interface ObserverReady<TInput extends Record<string, string>> {
|
|
|
15
21
|
readonly contract: () => ObserverHandle<TInput>;
|
|
16
22
|
}
|
|
17
23
|
|
|
24
|
+
interface CoverageRegistry {
|
|
25
|
+
}
|
|
26
|
+
type RegistryKeys = keyof CoverageRegistry;
|
|
27
|
+
type CoverageStatementId = [RegistryKeys] extends [never] ? string : Extract<RegistryKeys, string>;
|
|
28
|
+
|
|
18
29
|
type PreconditionRecord = Record<string, Precondition>;
|
|
19
30
|
type ResolveDeps<TDeps extends PreconditionRecord> = {
|
|
20
31
|
readonly [K in keyof TDeps]: PreconditionData<TDeps[K]>;
|
|
@@ -32,6 +43,13 @@ interface TestNeedsName {
|
|
|
32
43
|
}
|
|
33
44
|
interface TestNeedsRequires {
|
|
34
45
|
readonly description: (text: string) => TestNeedsRequires;
|
|
46
|
+
/**
|
|
47
|
+
* Declare the preconditions this test needs. The object keys become the
|
|
48
|
+
* destructured parameter in `.startsAt` / `.steps`, and each precondition's
|
|
49
|
+
* return data flows through as a typed proxy — interpolate proxy fields
|
|
50
|
+
* directly (e.g. `` `/workspaces/${workspace.id}` ``); never hand-write
|
|
51
|
+
* `{{namespace.key}}` template strings (lint blocks this).
|
|
52
|
+
*/
|
|
35
53
|
readonly requires: <TReqs extends PreconditionRecord>(reqs: TReqs) => TestNeedsOutcome<ResolveDeps<TReqs>>;
|
|
36
54
|
}
|
|
37
55
|
interface TestNeedsOutcome<TVars extends Record<string, Record<string, string>>> {
|
|
@@ -39,14 +57,34 @@ interface TestNeedsOutcome<TVars extends Record<string, Record<string, string>>>
|
|
|
39
57
|
}
|
|
40
58
|
|
|
41
59
|
interface TestNeedsStartsAt<TVars extends Record<string, Record<string, string>>> {
|
|
60
|
+
/**
|
|
61
|
+
* Skip implementation — compiles as a planning stub and is reported in
|
|
62
|
+
* `getUnimplemented()`. The test appears in the lockfile but is not run.
|
|
63
|
+
*/
|
|
42
64
|
readonly notImplemented: () => TestDefinition;
|
|
65
|
+
/**
|
|
66
|
+
* Starting URL for the test, derived from precondition data. The function
|
|
67
|
+
* receives the `.requires()` object destructured as typed proxies; it runs
|
|
68
|
+
* at compile time, not at test-author time.
|
|
69
|
+
*/
|
|
43
70
|
readonly startsAt: (fn: (vars: TVars) => string) => TestNeedsSteps<TVars>;
|
|
44
71
|
}
|
|
45
72
|
interface TestNeedsSteps<TVars extends Record<string, Record<string, string>>> {
|
|
73
|
+
/**
|
|
74
|
+
* Declare the ordered step list. Receives destructured precondition data as
|
|
75
|
+
* typed proxies (same as `.startsAt`). Every step must be labeled with
|
|
76
|
+
* `.as("…")` — lint enforces it.
|
|
77
|
+
*/
|
|
46
78
|
readonly steps: (fn: (vars: TVars) => ReadonlyArray<Step>) => TestNeedsCoverage;
|
|
47
79
|
}
|
|
48
80
|
interface TestNeedsCoverage {
|
|
49
|
-
|
|
81
|
+
/**
|
|
82
|
+
* Finalize the test and declare which mutation/AST branches it covers.
|
|
83
|
+
* Coverage IDs feed LLM-driven test scoping on diffs so only relevant tests
|
|
84
|
+
* run for a change. `.coverage()` (or `.notImplemented()`) is the only way
|
|
85
|
+
* to terminate the chain into a runnable `TestDefinition`.
|
|
86
|
+
*/
|
|
87
|
+
readonly coverage: (...ids: ReadonlyArray<CoverageStatementId>) => TestDefinition;
|
|
50
88
|
}
|
|
51
89
|
|
|
52
90
|
type PreconditionSetupResult<TData extends Record<string, string>> = {
|
|
@@ -79,9 +117,35 @@ interface RipploInstance<P extends PreconditionRegistry = PreconditionRegistry,
|
|
|
79
117
|
readonly getUnimplemented: () => UnimplementedItems;
|
|
80
118
|
}
|
|
81
119
|
type RipploBuilder = RipploInstance;
|
|
120
|
+
/**
|
|
121
|
+
* Declare a precondition — a named, reusable piece of test data setup. Returns
|
|
122
|
+
* a pure handle (no side effects at definition time); the setup/teardown impl
|
|
123
|
+
* is wired once in `createEngine`. Depend on other preconditions via
|
|
124
|
+
* `.requires()` so the DAG can resolve independents in parallel, giving every
|
|
125
|
+
* test a clean, isolated slate.
|
|
126
|
+
*/
|
|
82
127
|
declare function precondition(name: string): PreconditionNeedsSetup;
|
|
128
|
+
/**
|
|
129
|
+
* Declare a backend assertion — checked from tests via `assert.backend()`.
|
|
130
|
+
* The impl runs on your server (where DB/queue access lives) and is polled
|
|
131
|
+
* until pass/fail; `.budget()` picks the polling envelope. Use this instead
|
|
132
|
+
* of sleeps when verifying async side effects (jobs, webhooks, emails, DB rows).
|
|
133
|
+
*/
|
|
83
134
|
declare function observer(name: string): ObserverNeedsDescription;
|
|
135
|
+
/**
|
|
136
|
+
* Start a test definition. `id` is a stable kebab-case key persisted in the
|
|
137
|
+
* lockfile and used for run history — changing it renames the test and loses
|
|
138
|
+
* history. Set `options.uiOnly` only for genuinely read-only flows (no
|
|
139
|
+
* mutations); do not use it to silence observer lint on flows that mutate
|
|
140
|
+
* state — wire the observer instead.
|
|
141
|
+
*/
|
|
84
142
|
declare function test(id: string, options?: TestOptions): TestNeedsName;
|
|
143
|
+
/**
|
|
144
|
+
* The single registration point for the DSL graph. Collects the three
|
|
145
|
+
* registries into an instance consumed both by `ripplo compile` (to write
|
|
146
|
+
* `.ripplo/ripplo.lock`) and by `createEngine` on the server, where
|
|
147
|
+
* TypeScript exhaustiveness-checks that every handle has exactly one impl.
|
|
148
|
+
*/
|
|
85
149
|
declare function createRipplo<P extends PreconditionRegistry, O extends ObserverRegistry>(rawConfig: UserDslConfig, registries: RipploRegistries<P, O>): RipploInstance<P, O>;
|
|
86
150
|
|
|
87
|
-
export { type ObserverImplFn as O, type PreconditionImpl as P, type ResolveDeps as R, type ObserverRegistry as a, type PreconditionRecord as b, type PreconditionRegistry as c, type RipploBuilder as d, type RipploInstance as e, type RipploRegistries as f, createRipplo as g, observer as o, precondition as p, test as t };
|
|
151
|
+
export { type CoverageRegistry as C, type ObserverImplFn as O, type PreconditionImpl as P, type ResolveDeps as R, type ObserverRegistry as a, type PreconditionRecord as b, type PreconditionRegistry as c, type RipploBuilder as d, type RipploInstance as e, type RipploRegistries as f, createRipplo as g, observer as o, precondition as p, test as t };
|
package/dist/compiler.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Observer, Precondition, WorkflowSpec } from '@ripplo/spec';
|
|
2
|
-
import { d as RipploBuilder } from './builder-
|
|
2
|
+
import { d as RipploBuilder } from './builder-CkyzxH7O.js';
|
|
3
3
|
import { e as DslConfig } from './types-Do4o4Y_c.js';
|
|
4
4
|
import './step-De52hTLd.js';
|
|
5
5
|
import 'zod';
|
package/dist/control.d.ts
CHANGED
|
@@ -6,6 +6,12 @@ declare const VARIABLE_INTERNAL: unique symbol;
|
|
|
6
6
|
interface Variable<_TName extends string> {
|
|
7
7
|
readonly [VARIABLE_INTERNAL]: _TName;
|
|
8
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* Declare a runtime placeholder, bound later by `extract()` and consumed by
|
|
11
|
+
* actions/assertions. Use for values produced mid-test (e.g. an ID rendered
|
|
12
|
+
* into the DOM). Precondition data is already typed and injected — reach for
|
|
13
|
+
* `variable` only when the value isn't known until the test runs.
|
|
14
|
+
*/
|
|
9
15
|
declare function variable<TName extends string>(name: TName): Variable<TName>;
|
|
10
16
|
declare function readVariable(v: Variable<string>): string;
|
|
11
17
|
declare function isVariable(v: unknown): v is Variable<string>;
|
|
@@ -18,6 +24,11 @@ interface VariableRef {
|
|
|
18
24
|
readonly type: "variable";
|
|
19
25
|
}
|
|
20
26
|
declare function toStringValueRef(value: string | Variable<string>): StaticStringRef | VariableRef;
|
|
27
|
+
/**
|
|
28
|
+
* Capture the text of the matched element into `target` (a `variable()`).
|
|
29
|
+
* Pairs by name — downstream steps referencing the same `variable` see the
|
|
30
|
+
* extracted value.
|
|
31
|
+
*/
|
|
21
32
|
declare function extract(locator: AnyLocator, target: Variable<string>): UnlabeledStep<{
|
|
22
33
|
locator: {
|
|
23
34
|
by: "testId";
|
package/dist/elysia.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Elysia } from 'elysia';
|
|
2
|
-
import { R as RipploEngine } from './engine-
|
|
3
|
-
import './builder-
|
|
2
|
+
import { R as RipploEngine } from './engine-CRq3Az6b.js';
|
|
3
|
+
import './builder-CkyzxH7O.js';
|
|
4
4
|
import './types-Do4o4Y_c.js';
|
|
5
5
|
import 'zod';
|
|
6
6
|
import './step-De52hTLd.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as PreconditionRegistry, a as ObserverRegistry, O as ObserverImplFn, P as PreconditionImpl, e as RipploInstance } from './builder-
|
|
1
|
+
import { c as PreconditionRegistry, a as ObserverRegistry, O as ObserverImplFn, P as PreconditionImpl, e as RipploInstance } from './builder-CkyzxH7O.js';
|
|
2
2
|
import { h as ObserverOutcome, C as CookieEntry, e as DslConfig, g as ObserverDefinition, k as PreconditionDefinition, U as UnimplementedItems, O as ObserverHandle, P as Precondition } from './types-Do4o4Y_c.js';
|
|
3
3
|
|
|
4
4
|
interface EngineResult {
|
package/dist/express.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
|
-
import { R as RipploEngine } from './engine-
|
|
3
|
-
import './builder-
|
|
2
|
+
import { R as RipploEngine } from './engine-CRq3Az6b.js';
|
|
3
|
+
import './builder-CkyzxH7O.js';
|
|
4
4
|
import './types-Do4o4Y_c.js';
|
|
5
5
|
import 'zod';
|
|
6
6
|
import './step-De52hTLd.js';
|
package/dist/fastify.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FastifyInstance } from 'fastify';
|
|
2
|
-
import { R as RipploEngine } from './engine-
|
|
3
|
-
import './builder-
|
|
2
|
+
import { R as RipploEngine } from './engine-CRq3Az6b.js';
|
|
3
|
+
import './builder-CkyzxH7O.js';
|
|
4
4
|
import './types-Do4o4Y_c.js';
|
|
5
5
|
import 'zod';
|
|
6
6
|
import './step-De52hTLd.js';
|
package/dist/hono.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
|
-
import { R as RipploEngine } from './engine-
|
|
3
|
-
import './builder-
|
|
2
|
+
import { R as RipploEngine } from './engine-CRq3Az6b.js';
|
|
3
|
+
import './builder-CkyzxH7O.js';
|
|
4
4
|
import './types-Do4o4Y_c.js';
|
|
5
5
|
import 'zod';
|
|
6
6
|
import './step-De52hTLd.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { O as ObserverImplFn, a as ObserverRegistry, P as PreconditionImpl, b as PreconditionRecord, c as PreconditionRegistry, R as ResolveDeps, d as RipploBuilder, e as RipploInstance, f as RipploRegistries, g as createRipplo, o as observer, p as precondition, t as test } from './builder-
|
|
1
|
+
export { C as CoverageRegistry, O as ObserverImplFn, a as ObserverRegistry, P as PreconditionImpl, b as PreconditionRecord, c as PreconditionRegistry, R as ResolveDeps, d as RipploBuilder, e as RipploInstance, f as RipploRegistries, g as createRipplo, o as observer, p as precondition, t as test } from './builder-CkyzxH7O.js';
|
|
2
2
|
import { CompileResult } from './compiler.js';
|
|
3
3
|
export { CompiledTest, compile } from './compiler.js';
|
|
4
|
-
export { E as EngineImpls, a as EngineResult, b as ExecuteBatchOptions, N as NotImplemented, O as ObserverImplFnFor, P as PreconditionImplFor, R as RipploEngine, c as createEngine, n as notImplemented } from './engine-
|
|
4
|
+
export { E as EngineImpls, a as EngineResult, b as ExecuteBatchOptions, N as NotImplemented, O as ObserverImplFnFor, P as PreconditionImplFor, R as RipploEngine, c as createEngine, n as notImplemented } from './engine-CRq3Az6b.js';
|
|
5
5
|
import { C as CookieEntry } from './types-Do4o4Y_c.js';
|
|
6
6
|
export { c as CookieOptions, D as DEFAULT_IGNORE_PATHS, d as DEFAULT_WATCH_PATHS, e as DslConfig, f as ObserverContext, g as ObserverDefinition, O as ObserverHandle, a as ObserverInput, h as ObserverOutcome, P as Precondition, i as PreconditionDeps, S as SetupContext, T as TeardownContext, j as TestDefinition } from './types-Do4o4Y_c.js';
|
|
7
7
|
export { D as DslNodeInput } from './step-De52hTLd.js';
|
package/dist/koa.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Middleware } from 'koa';
|
|
2
|
-
import { R as RipploEngine } from './engine-
|
|
3
|
-
import './builder-
|
|
2
|
+
import { R as RipploEngine } from './engine-CRq3Az6b.js';
|
|
3
|
+
import './builder-CkyzxH7O.js';
|
|
4
4
|
import './types-Do4o4Y_c.js';
|
|
5
5
|
import 'zod';
|
|
6
6
|
import './step-De52hTLd.js';
|
package/dist/locators.d.ts
CHANGED
|
@@ -24,7 +24,17 @@ type AnyLocator = Locator<"role" | "testId">;
|
|
|
24
24
|
type InputLocator = Locator<"testId"> | RoleLocator<"combobox" | "searchbox" | "spinbutton" | "textbox">;
|
|
25
25
|
type SelectLocator = Locator<"testId"> | RoleLocator<"combobox" | "listbox">;
|
|
26
26
|
type CheckLocator = Locator<"testId"> | RoleLocator<"checkbox" | "switch">;
|
|
27
|
+
/**
|
|
28
|
+
* Preferred locator: targets an element by its ARIA role and accessible name.
|
|
29
|
+
* Survives DOM churn and doubles as an accessibility check — if a role query
|
|
30
|
+
* can't find your element, real users likely can't either.
|
|
31
|
+
*/
|
|
27
32
|
declare function role<TRole extends AriaRole>(ariaRole: TRole, name?: string): RoleLocator<TRole>;
|
|
33
|
+
/**
|
|
34
|
+
* Escape hatch for elements without a semantic role (decorative wrappers,
|
|
35
|
+
* non-interactive panels). Prefer `role()` when the element has one; a
|
|
36
|
+
* test-id locator has no accessibility signal.
|
|
37
|
+
*/
|
|
28
38
|
declare function testId(id: string): Locator<"testId">;
|
|
29
39
|
|
|
30
40
|
export { type AnyLocator, type AriaRole, type CheckLocator, type InputLocator, type Locator, type LocatorSpec, type RoleLocator, type SelectLocator, readLocator, role, testId };
|
package/dist/lockfile.d.ts
CHANGED
package/dist/nestjs.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DynamicModule } from '@nestjs/common';
|
|
2
|
-
import { R as RipploEngine } from './engine-
|
|
3
|
-
import './builder-
|
|
2
|
+
import { R as RipploEngine } from './engine-CRq3Az6b.js';
|
|
3
|
+
import './builder-CkyzxH7O.js';
|
|
4
4
|
import './types-Do4o4Y_c.js';
|
|
5
5
|
import 'zod';
|
|
6
6
|
import './step-De52hTLd.js';
|
package/dist/nextjs.d.ts
CHANGED