@ripplo/testing 0.5.2 → 0.5.4

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 CHANGED
@@ -256,12 +256,14 @@ Each batched setup item exposes `ctx`:
256
256
 
257
257
  - `ctx.runId` — 12-char run id.
258
258
  - `ctx.fixed(value)` — static test value, type-branded so the engine can tell it apart from a raw literal.
259
- - `ctx.uniqueId(prefix)` returns `ripplo-test-<prefix>-<runId>`.
260
- - `ctx.uniqueEmail()` returns `ripplo-test-<runId>@test.ripplo.ai`.
259
+ - `ctx.uniqueId(prefix)` returns `ripplo-test-<prefix>-<runId>-<n>`, where `n` is a per-call counter scoped to the run. Calling it repeatedly yields distinct values.
260
+ - `ctx.uniqueEmail()` returns `ripplo-test-<runId>-<n>@test.ripplo.ai`, same per-call counter.
261
261
  - `ctx.setCookie(name, value, options?)` applies to that run's browser context before the test starts.
262
262
 
263
263
  Helpers return plain primitives, but the return type is branded — a bare string literal in a `setup` return fails at compile time, which is what stops tests from accidentally seeding identical-looking data across runs.
264
264
 
265
+ The shared prefix (`ripplo-test-`) is also exported as `TEST_ID_PREFIX` from `@ripplo/testing`, so teardown / cleanup logic that scopes `WHERE` clauses by `startsWith(TEST_ID_PREFIX)` doesn't have to hardcode the string.
266
+
265
267
  ### Observer context
266
268
 
267
269
  The observer impl returns one of three terminal states:
package/dist/actions.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  readVariable,
3
3
  toSpecLocator,
4
4
  toStringValueRef
5
- } from "./chunk-YJ4KB56W.js";
5
+ } from "./chunk-2YLI7VD4.js";
6
6
  import "./chunk-DCJBLS2U.js";
7
7
  import {
8
8
  createStep
@@ -14,10 +14,16 @@ var Fixture = class {
14
14
  kind = "fixture";
15
15
  name;
16
16
  constructor(name) {
17
- if (name.length === 0) {
17
+ const raw = name;
18
+ if (typeof raw !== "string") {
19
+ throw new TypeError(
20
+ `fixture(name) requires a string name \u2014 got ${raw == null ? String(raw) : typeof raw}`
21
+ );
22
+ }
23
+ if (raw.length === 0) {
18
24
  throw new Error("fixture(name) requires a non-empty name");
19
25
  }
20
- this.name = name;
26
+ this.name = raw;
21
27
  }
22
28
  };
23
29
  function fixture(name) {
@@ -65,8 +71,32 @@ function hover(locator) {
65
71
  function press(key) {
66
72
  return createStep({ key, type: "press" });
67
73
  }
74
+ function describeFilesArg(files) {
75
+ if (typeof files === "string") {
76
+ return `string "${files}"`;
77
+ }
78
+ return typeof files;
79
+ }
80
+ function normalizeUploadFiles(files) {
81
+ if (files instanceof Fixture) {
82
+ return [files];
83
+ }
84
+ if (!Array.isArray(files)) {
85
+ throw new TypeError(
86
+ `upload() expected a Fixture or an array of Fixtures \u2014 got ${describeFilesArg(files)}. Wrap the filename with fixture(): upload(loc, fixture("file.png"))`
87
+ );
88
+ }
89
+ return files.map((f, i) => {
90
+ if (!(f instanceof Fixture)) {
91
+ throw new TypeError(
92
+ `upload() files[${String(i)}] is not a Fixture \u2014 wrap it with fixture(): upload(loc, fixture("file.png"))`
93
+ );
94
+ }
95
+ return f;
96
+ });
97
+ }
68
98
  function upload(locator, files, options) {
69
- const list = files instanceof Fixture ? [files] : [...files];
99
+ const list = normalizeUploadFiles(files);
70
100
  return createStep({
71
101
  files: list.map((f) => f.name),
72
102
  locator: toSpecLocator(locator),
package/dist/assert.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  toSpecLocator,
7
7
  toStringValueRef
8
- } from "./chunk-YJ4KB56W.js";
8
+ } from "./chunk-2YLI7VD4.js";
9
9
  import "./chunk-DCJBLS2U.js";
10
10
  import {
11
11
  createStep
@@ -153,4 +153,4 @@ declare function test(id: string, options?: TestOptions): TestNeedsName;
153
153
  */
154
154
  declare function createRipplo<P extends PreconditionRegistry, O extends ObserverRegistry>(registries: RipploRegistries<P, O>): RipploInstance<P, O>;
155
155
 
156
- 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 };
156
+ 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 PreconditionSetupItem as d, type PreconditionTeardownItem as e, type RipploBuilder as f, type RipploInstance as g, type RipploRegistries as h, createRipplo as i, observer as o, precondition as p, test as t };
@@ -38,6 +38,13 @@ function toStringValueRef(value) {
38
38
  if (typeof value === "string") {
39
39
  return { type: "static", value };
40
40
  }
41
+ if (!isVariable(value)) {
42
+ const raw = value;
43
+ const got = raw == null ? String(raw) : typeof raw;
44
+ throw new TypeError(
45
+ `Expected a string or variable() \u2014 got ${got}. Wrap dynamic values with variable("name") and pair them with extract().`
46
+ );
47
+ }
41
48
  return { name: readVariable(value), type: "variable" };
42
49
  }
43
50
  function extract(locator, target) {
@@ -1,5 +1,5 @@
1
1
  import { Observer, Precondition, WorkflowSpec } from '@ripplo/spec';
2
- import { d as RipploBuilder } from './builder-DiVz3t1D.js';
2
+ import { f as RipploBuilder } from './builder-SsgqYqSC.js';
3
3
  import './types-BzZrl65Z.js';
4
4
  import './step-De52hTLd.js';
5
5
 
package/dist/control.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  readVariable,
5
5
  toStringValueRef,
6
6
  variable
7
- } from "./chunk-YJ4KB56W.js";
7
+ } from "./chunk-2YLI7VD4.js";
8
8
  import "./chunk-DCJBLS2U.js";
9
9
  import "./chunk-MGATMMCZ.js";
10
10
  import "./chunk-4MGIQFAJ.js";
package/dist/elysia.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Elysia } from 'elysia';
2
- import { R as RipploEngine } from './engine-DVbF4E5A.js';
3
- import './builder-DiVz3t1D.js';
2
+ import { R as RipploEngine } from './engine-BOqzK_go.js';
3
+ import './builder-SsgqYqSC.js';
4
4
  import './types-BzZrl65Z.js';
5
5
  import './step-De52hTLd.js';
6
6
  import '@ripplo/spec';
@@ -1,6 +1,7 @@
1
- import { c as PreconditionRegistry, a as ObserverRegistry, O as ObserverImplFn, P as PreconditionImpl, e as RipploInstance } from './builder-DiVz3t1D.js';
1
+ import { c as PreconditionRegistry, a as ObserverRegistry, O as ObserverImplFn, P as PreconditionImpl, g as RipploInstance } from './builder-SsgqYqSC.js';
2
2
  import { P as Primitive, g as ObserverOutcome, C as CookieEntry, f as ObserverDefinition, l as PreconditionDefinition, U as UnimplementedItems, O as ObserverHandle, h as Precondition } from './types-BzZrl65Z.js';
3
3
 
4
+ declare const TEST_ID_PREFIX = "ripplo-test-";
4
5
  interface EngineRunResult {
5
6
  readonly cookies: ReadonlyArray<CookieEntry>;
6
7
  readonly data: Record<string, Record<string, Primitive>>;
@@ -57,4 +58,4 @@ interface EngineImpls<P extends PreconditionRegistry, O extends ObserverRegistry
57
58
  }
58
59
  declare function createEngine<P extends PreconditionRegistry, O extends ObserverRegistry>(ripplo: RipploInstance<P, O>, impls: EngineImpls<P, O>): RipploEngine;
59
60
 
60
- export { type EngineRunResult as E, type NotImplemented as N, type ObserverImplFnFor as O, type PreconditionImplFor as P, type RipploEngine as R, type TeardownRunResult as T, type EngineImpls as a, type ExecuteBatchItem as b, type ExecuteBatchOptions as c, type TeardownBatchItem as d, createEngine as e, notImplemented as n };
61
+ export { type EngineRunResult as E, type NotImplemented as N, type ObserverImplFnFor as O, type PreconditionImplFor as P, type RipploEngine as R, type TeardownRunResult as T, type EngineImpls as a, type ExecuteBatchItem as b, type ExecuteBatchOptions as c, TEST_ID_PREFIX as d, type TeardownBatchItem as e, createEngine as f, notImplemented as n };
package/dist/express.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Router } from 'express';
2
- import { R as RipploEngine } from './engine-DVbF4E5A.js';
3
- import './builder-DiVz3t1D.js';
2
+ import { R as RipploEngine } from './engine-BOqzK_go.js';
3
+ import './builder-SsgqYqSC.js';
4
4
  import './types-BzZrl65Z.js';
5
5
  import './step-De52hTLd.js';
6
6
  import '@ripplo/spec';
package/dist/fastify.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { FastifyInstance } from 'fastify';
2
- import { R as RipploEngine } from './engine-DVbF4E5A.js';
3
- import './builder-DiVz3t1D.js';
2
+ import { R as RipploEngine } from './engine-BOqzK_go.js';
3
+ import './builder-SsgqYqSC.js';
4
4
  import './types-BzZrl65Z.js';
5
5
  import './step-De52hTLd.js';
6
6
  import '@ripplo/spec';
package/dist/hono.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Hono } from 'hono';
2
- import { R as RipploEngine } from './engine-DVbF4E5A.js';
3
- import './builder-DiVz3t1D.js';
2
+ import { R as RipploEngine } from './engine-BOqzK_go.js';
3
+ import './builder-SsgqYqSC.js';
4
4
  import './types-BzZrl65Z.js';
5
5
  import './step-De52hTLd.js';
6
6
  import '@ripplo/spec';
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
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-DiVz3t1D.js';
1
+ export { C as CoverageRegistry, O as ObserverImplFn, a as ObserverRegistry, P as PreconditionImpl, b as PreconditionRecord, c as PreconditionRegistry, d as PreconditionSetupItem, e as PreconditionTeardownItem, R as ResolveDeps, f as RipploBuilder, g as RipploInstance, h as RipploRegistries, i as createRipplo, o as observer, p as precondition, t as test } from './builder-SsgqYqSC.js';
2
2
  import { CompileResult } from './compiler.js';
3
3
  export { CompiledTest, compile } from './compiler.js';
4
- import { E as EngineRunResult, T as TeardownRunResult$1 } from './engine-DVbF4E5A.js';
5
- export { a as EngineImpls, b as ExecuteBatchItem, c as ExecuteBatchOptions, N as NotImplemented, O as ObserverImplFnFor, P as PreconditionImplFor, R as RipploEngine, d as TeardownBatchItem, e as createEngine, n as notImplemented } from './engine-DVbF4E5A.js';
4
+ import { E as EngineRunResult, T as TeardownRunResult$1 } from './engine-BOqzK_go.js';
5
+ export { a as EngineImpls, b as ExecuteBatchItem, c as ExecuteBatchOptions, N as NotImplemented, O as ObserverImplFnFor, P as PreconditionImplFor, R as RipploEngine, d as TEST_ID_PREFIX, e as TeardownBatchItem, f as createEngine, n as notImplemented } from './engine-BOqzK_go.js';
6
6
  import { C as CookieEntry } from './types-BzZrl65Z.js';
7
7
  export { c as CookieOptions, D as DEFAULT_IGNORE_PATHS, d as DEFAULT_WATCH_PATHS, e as ObserverContext, f as ObserverDefinition, O as ObserverHandle, a as ObserverInput, g as ObserverOutcome, h as Precondition, i as PreconditionDeps, P as Primitive, S as SetupContext, T as TeardownContext, j as TestDefinition, k as TestValue } from './types-BzZrl65Z.js';
8
8
  export { D as DslNodeInput } from './step-De52hTLd.js';
package/dist/index.js CHANGED
@@ -849,6 +849,7 @@ var RULES = [
849
849
  ];
850
850
 
851
851
  // src/engine.ts
852
+ var TEST_ID_PREFIX = "ripplo-test-";
852
853
  function notImplemented(reason) {
853
854
  return { reason: reason ?? "not implemented" };
854
855
  }
@@ -1232,6 +1233,11 @@ function createSetupContext({
1232
1233
  defaultDomain,
1233
1234
  runId
1234
1235
  }) {
1236
+ let callCounter = 0;
1237
+ const nextSuffix = () => {
1238
+ callCounter += 1;
1239
+ return `${runId}-${String(callCounter)}`;
1240
+ };
1235
1241
  return {
1236
1242
  runId,
1237
1243
  fixed: (value) => brandTestValue(value),
@@ -1239,8 +1245,8 @@ function createSetupContext({
1239
1245
  const resolvedOptions = options != null && options.domain == null && defaultDomain != null ? { ...options, domain: defaultDomain } : options ?? void 0;
1240
1246
  cookies.push({ name, options: resolvedOptions, value });
1241
1247
  },
1242
- uniqueEmail: () => brandTestValue(`ripplo-test-${runId}@test.ripplo.ai`),
1243
- uniqueId: (prefix) => brandTestValue(`ripplo-test-${prefix}-${runId}`)
1248
+ uniqueEmail: () => brandTestValue(`${TEST_ID_PREFIX}${nextSuffix()}@test.ripplo.ai`),
1249
+ uniqueId: (prefix) => brandTestValue(`${TEST_ID_PREFIX}${prefix}-${nextSuffix()}`)
1244
1250
  };
1245
1251
  }
1246
1252
  function deriveDefaultDomain(baseUrl) {
@@ -1256,6 +1262,7 @@ function deriveDefaultDomain(baseUrl) {
1256
1262
  export {
1257
1263
  DEFAULT_IGNORE_PATHS,
1258
1264
  DEFAULT_WATCH_PATHS,
1265
+ TEST_ID_PREFIX,
1259
1266
  compile,
1260
1267
  createEngine,
1261
1268
  createRipplo,
package/dist/koa.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Middleware } from 'koa';
2
- import { R as RipploEngine } from './engine-DVbF4E5A.js';
3
- import './builder-DiVz3t1D.js';
2
+ import { R as RipploEngine } from './engine-BOqzK_go.js';
3
+ import './builder-SsgqYqSC.js';
4
4
  import './types-BzZrl65Z.js';
5
5
  import './step-De52hTLd.js';
6
6
  import '@ripplo/spec';
@@ -1,7 +1,7 @@
1
1
  import { Codec } from '@ripplo/spec';
2
2
  import { z } from 'zod';
3
3
  import { CompileResult } from './compiler.js';
4
- import './builder-DiVz3t1D.js';
4
+ import './builder-SsgqYqSC.js';
5
5
  import './types-BzZrl65Z.js';
6
6
  import './step-De52hTLd.js';
7
7
 
@@ -714,8 +714,9 @@ declare function hashFixturesIntoCompileResult({ cwd, result, }: HashFixturesPar
714
714
  type LockfileComparison = "match" | "missing" | "stale";
715
715
  interface CompareLockfileParams {
716
716
  readonly compiled: CompileResult;
717
+ readonly cwd: string;
717
718
  readonly existing: Lockfile | null;
718
719
  }
719
- declare function compareCompileToLockfile({ compiled, existing, }: CompareLockfileParams): LockfileComparison;
720
+ declare function compareCompileToLockfile({ compiled, cwd, existing, }: CompareLockfileParams): Promise<LockfileComparison>;
720
721
 
721
722
  export { type CompareLockfileParams, FIXTURES_RELATIVE_PATH, type FixtureEntry, LOCKFILE_RELATIVE_PATH, type Lockfile, type LockfileComparison, type ReadLockfileParams, type WriteLockfileParams, compareCompileToLockfile, compileResultToLockfile, hashFixturesIntoCompileResult, lockfileCodec, readLockfile, serializeLockfile, writeLockfile };
package/dist/lockfile.js CHANGED
@@ -642,14 +642,16 @@ function collectFixtureReferences(result) {
642
642
  });
643
643
  return names;
644
644
  }
645
- function compareCompileToLockfile({
645
+ async function compareCompileToLockfile({
646
646
  compiled,
647
+ cwd,
647
648
  existing
648
649
  }) {
649
650
  if (existing == null) {
650
651
  return "missing";
651
652
  }
652
- const fresh = serializeLockfile(compileResultToLockfile(compiled));
653
+ const hydrated = await hashFixturesIntoCompileResult({ cwd, result: compiled });
654
+ const fresh = serializeLockfile(compileResultToLockfile(hydrated));
653
655
  const current = serializeLockfile(existing);
654
656
  return fresh === current ? "match" : "stale";
655
657
  }
package/dist/nestjs.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { DynamicModule } from '@nestjs/common';
2
- import { R as RipploEngine } from './engine-DVbF4E5A.js';
3
- import './builder-DiVz3t1D.js';
2
+ import { R as RipploEngine } from './engine-BOqzK_go.js';
3
+ import './builder-SsgqYqSC.js';
4
4
  import './types-BzZrl65Z.js';
5
5
  import './step-De52hTLd.js';
6
6
  import '@ripplo/spec';
package/dist/nextjs.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as RipploEngine } from './engine-DVbF4E5A.js';
2
- import './builder-DiVz3t1D.js';
1
+ import { R as RipploEngine } from './engine-BOqzK_go.js';
2
+ import './builder-SsgqYqSC.js';
3
3
  import './types-BzZrl65Z.js';
4
4
  import './step-De52hTLd.js';
5
5
  import '@ripplo/spec';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ripplo/testing",
3
3
  "description": "TypeScript DSL for defining and running Ripplo e2e workflow tests",
4
- "version": "0.5.2",
4
+ "version": "0.5.4",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist"