@voltro/testing 0.85.0 → 0.86.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/CHANGELOG.md +666 -0
- package/THIRD-PARTY-NOTICES.md +5 -33
- package/dist/client.js +73 -98
- package/dist/dialect.js +244 -145
- package/dist/factory.js +65 -0
- package/dist/fixtureRow.js +30 -0
- package/dist/formBindingHarness.js +46 -0
- package/dist/hydrateFixtureRows.js +22 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +19 -933
- package/dist/invoke.js +44 -0
- package/dist/mockClock.js +78 -0
- package/dist/mockLLM.js +19 -0
- package/dist/mockWebhooks.js +26 -0
- package/dist/platform.js +1 -5
- package/dist/reachable.js +27 -0
- package/dist/serviceApiMock.js +53 -0
- package/dist/subject.js +11 -0
- package/dist/subscribeContext.js +16 -0
- package/dist/testApps.js +111 -0
- package/dist/testContext.js +248 -0
- package/dist/testEventBus.js +73 -0
- package/dist/testRequest.js +119 -0
- package/dist/workflowRunner.js +85 -0
- package/package.json +9 -9
package/dist/factory.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { fixtureRow as e, nextSequence as t } from "./fixtureRow.js";
|
|
2
|
+
import { missingRequiredColumns as n } from "@voltro/database";
|
|
3
|
+
//#region src/factory.ts
|
|
4
|
+
var r = (e) => {
|
|
5
|
+
let n = {};
|
|
6
|
+
for (let [r, i] of Object.entries(e)) n[r] = typeof i == "function" ? i(t()) : i;
|
|
7
|
+
return n;
|
|
8
|
+
}, i = (e) => {
|
|
9
|
+
for (let [t, n] of Object.entries(e.fields)) if (n.type === "id") return t;
|
|
10
|
+
return "id";
|
|
11
|
+
}, a = async (e, t, r, a, s) => {
|
|
12
|
+
let c = {};
|
|
13
|
+
for (let l of n(t, r)) {
|
|
14
|
+
let n = t.fields[l];
|
|
15
|
+
if (n === void 0 || n.type !== "reference" || n.references === void 0) continue;
|
|
16
|
+
let r = n.references();
|
|
17
|
+
if (s.includes(r.tableName)) throw Error(`defineFactory: creating '${t.tableName}' requires '${r.tableName}' via '${l}', and that reference is cyclic (${[...s, r.tableName].join(" → ")}). Insert one side first and pass the id: create(store, { ${l}: existing.id }).`);
|
|
18
|
+
let u = a[l];
|
|
19
|
+
c[l] = (u === void 0 ? await o(e, r, {}, {}, [...s, r.tableName]) : await u.create(e, {}))[n.referenceColumn ?? i(r)];
|
|
20
|
+
}
|
|
21
|
+
return c;
|
|
22
|
+
}, o = async (t, n, r, i, o) => {
|
|
23
|
+
let s = {
|
|
24
|
+
...await a(t, n, r, i, o),
|
|
25
|
+
...r
|
|
26
|
+
};
|
|
27
|
+
return t.insert(n.tableName, e(n, s));
|
|
28
|
+
}, s = (e, t) => typeof e == "function" ? e(t) : e ?? {}, c = (t, n = {}) => {
|
|
29
|
+
let i = n.traits ?? {}, a = n.associations ?? {}, c = (n) => {
|
|
30
|
+
let l = (e = {}) => ({
|
|
31
|
+
...r(n),
|
|
32
|
+
...e
|
|
33
|
+
}), u = (n = {}) => e(t, l(n));
|
|
34
|
+
return {
|
|
35
|
+
table: t,
|
|
36
|
+
build: u,
|
|
37
|
+
buildList: (e, t) => Array.from({ length: e }, (e, n) => u(s(t, n))),
|
|
38
|
+
create: (e, n = {}) => o(e, t, l(n), a, [t.tableName]),
|
|
39
|
+
createList: async (e, n, r) => {
|
|
40
|
+
let i = [];
|
|
41
|
+
for (let c = 0; c < n; c++) i.push(await o(e, t, l(s(r, c)), a, [t.tableName]));
|
|
42
|
+
return i;
|
|
43
|
+
},
|
|
44
|
+
with: (...e) => {
|
|
45
|
+
let r = n;
|
|
46
|
+
for (let n of e) {
|
|
47
|
+
let e = i[n];
|
|
48
|
+
if (e === void 0) throw Error(`defineFactory: '${t.tableName}' has no trait '${n}'. Declared: ${Object.keys(i).join(", ") || "(none)"}.`);
|
|
49
|
+
r = {
|
|
50
|
+
...r,
|
|
51
|
+
...e
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return c(r);
|
|
55
|
+
},
|
|
56
|
+
extend: (e) => c({
|
|
57
|
+
...n,
|
|
58
|
+
...e
|
|
59
|
+
})
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
return c(n.defaults ?? {});
|
|
63
|
+
};
|
|
64
|
+
//#endregion
|
|
65
|
+
export { c as defineFactory };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { AUTO_FILLED_COLUMNS as e, missingRequiredColumns as t } from "@voltro/database";
|
|
2
|
+
//#region src/fixtureRow.ts
|
|
3
|
+
var n = new Set(e), r = 0, i = () => ++r, a = (e, t) => {
|
|
4
|
+
if (t.oneOf && t.oneOf.length > 0) return t.oneOf[0];
|
|
5
|
+
if (t.enumValues && t.enumValues.length > 0) return t.enumValues[0];
|
|
6
|
+
let n = t.unique === !0;
|
|
7
|
+
switch (t.type) {
|
|
8
|
+
case "text":
|
|
9
|
+
case "id":
|
|
10
|
+
case "enum": return n ? `${e}-${++r}` : e;
|
|
11
|
+
case "reference": return t.referenceStorage === "numeric" ? n ? ++r : 0 : n ? `${e}-${++r}` : e;
|
|
12
|
+
case "integer":
|
|
13
|
+
case "real": return n ? ++r : 0;
|
|
14
|
+
case "decimal":
|
|
15
|
+
case "bigint": return n ? String(++r) : "0";
|
|
16
|
+
case "boolean": return !1;
|
|
17
|
+
case "timestamp":
|
|
18
|
+
case "date": return /* @__PURE__ */ new Date(0);
|
|
19
|
+
default: throw Error(`fixtureRow: column '${e}' is a required '${t.type}' with no default, and fixtureRow can't synthesize a safe placeholder for that type. Pass it explicitly: fixtureRow(table, { ${e}: … }).`);
|
|
20
|
+
}
|
|
21
|
+
}, o = (e, r = {}) => {
|
|
22
|
+
let i = {};
|
|
23
|
+
for (let o of t(e, r)) n.has(o) || (i[o] = a(o, e.fields[o]));
|
|
24
|
+
return {
|
|
25
|
+
...i,
|
|
26
|
+
...r
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
//#endregion
|
|
30
|
+
export { o as fixtureRow, i as nextSequence };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { makeVoltroTestClient as e } from "./client.js";
|
|
2
|
+
import { act as t, createElement as n } from "react";
|
|
3
|
+
import { useFormBinding as r } from "@voltro/client";
|
|
4
|
+
//#region src/formBindingHarness.tsx
|
|
5
|
+
var i = async (i, a = {}) => {
|
|
6
|
+
if (globalThis.document === void 0) throw Error("renderFormBinding needs a DOM to render hooks — add `// @vitest-environment jsdom` to the spec.");
|
|
7
|
+
let { createRoot: o } = await import("react-dom/client"), s = a.apiName ?? "app", c = e({
|
|
8
|
+
apiName: s,
|
|
9
|
+
...a.client ?? {},
|
|
10
|
+
mutations: {
|
|
11
|
+
[i]: a.mutation ?? (() => ({ ok: !0 })),
|
|
12
|
+
...a.client?.mutations ?? {}
|
|
13
|
+
}
|
|
14
|
+
}), l, u = () => (l = r(s, i, a.binding ?? {}), null), d = o(globalThis.document.createElement("div"));
|
|
15
|
+
return await t(async () => {
|
|
16
|
+
d.render(n(c.Provider, null, n(u)));
|
|
17
|
+
}), {
|
|
18
|
+
binding: () => l,
|
|
19
|
+
fill: (e, n) => {
|
|
20
|
+
t(() => {
|
|
21
|
+
l.field(e).setValue(n);
|
|
22
|
+
});
|
|
23
|
+
},
|
|
24
|
+
blur: (e) => {
|
|
25
|
+
t(() => {
|
|
26
|
+
l.field(e).onBlur();
|
|
27
|
+
});
|
|
28
|
+
},
|
|
29
|
+
submit: async () => {
|
|
30
|
+
let e;
|
|
31
|
+
return await t(async () => {
|
|
32
|
+
e = await l.submit();
|
|
33
|
+
}), e;
|
|
34
|
+
},
|
|
35
|
+
errors: () => l.errors,
|
|
36
|
+
state: () => l.state,
|
|
37
|
+
client: c,
|
|
38
|
+
unmount: () => {
|
|
39
|
+
t(() => {
|
|
40
|
+
d.unmount();
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
//#endregion
|
|
46
|
+
export { i as renderFormBinding };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Result as e, Schema as t } from "effect";
|
|
2
|
+
//#region src/hydrateFixtureRows.ts
|
|
3
|
+
var n = t.decodeUnknownResult(t.DateFromString), r = /^\d{4}-\d{2}-\d{2}$/, i = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/, a = (t, a) => {
|
|
4
|
+
if (typeof t != "string" || !i.test(t) && !(a === "date" && r.test(t))) return !1;
|
|
5
|
+
let o = t.slice(0, 10), s = n(o);
|
|
6
|
+
return e.isSuccess(s) && Number.isFinite(s.success.getTime()) && s.success.toISOString().slice(0, 10) === o;
|
|
7
|
+
}, o = (t, r) => {
|
|
8
|
+
let i = Object.entries(t.fields).filter(([, e]) => e.type === "timestamp" || e.type === "date");
|
|
9
|
+
return r.map((r, o) => {
|
|
10
|
+
let s = { ...r };
|
|
11
|
+
for (let [c, l] of i) {
|
|
12
|
+
let i = r[c];
|
|
13
|
+
if (i == null || i instanceof Date && Number.isFinite(i.getTime())) continue;
|
|
14
|
+
let u = n(i);
|
|
15
|
+
if (!a(i, l.type) || e.isFailure(u) || !Number.isFinite(u.success.getTime())) throw TypeError(`hydrateFixtureRows: table '${t.tableName}', row ${o}, column '${c}' requires a valid Date or ISO date-time with Z or an offset${l.type === "date" ? " (YYYY-MM-DD is also accepted as UTC midnight)" : ""}.`);
|
|
16
|
+
s[c] = u.success;
|
|
17
|
+
}
|
|
18
|
+
return s;
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
//#endregion
|
|
22
|
+
export { o as hydrateFixtureRows };
|
package/dist/index.d.ts
CHANGED
|
@@ -1094,13 +1094,13 @@ export declare interface TestResponse {
|
|
|
1094
1094
|
readonly headers: Readonly<Record<string, string | ReadonlyArray<string>>>;
|
|
1095
1095
|
/** The raw response body as text (empty string when there was none). */
|
|
1096
1096
|
readonly text: string;
|
|
1097
|
-
/**
|
|
1098
|
-
|
|
1099
|
-
|
|
1097
|
+
/** Byte-exact buffered body, including a consumed finite byte stream. SSE remains unconsumed. */
|
|
1098
|
+
readonly bytes?: Uint8Array;
|
|
1099
|
+
/** Parsed JSON when the response has a JSON content-type; otherwise
|
|
1100
|
+
* `undefined`. SSE responses remain unconsumed. */
|
|
1100
1101
|
readonly body: unknown;
|
|
1101
|
-
/**
|
|
1102
|
-
* `text
|
|
1103
|
-
* looking like an empty 200. */
|
|
1102
|
+
/** True for SSE and byte streams. Finite byte streams populate `bytes` and
|
|
1103
|
+
* `text`; SSE remains unconsumed, with empty text and undefined body. */
|
|
1104
1104
|
readonly stream: boolean;
|
|
1105
1105
|
}
|
|
1106
1106
|
|