@substrat-run/contract-tests 0.127.0 → 0.129.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/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modules.d.ts +2 -0
- package/dist/modules.d.ts.map +1 -1
- package/dist/modules.js +48 -0
- package/dist/modules.js.map +1 -1
- package/dist/permission-suite.d.ts.map +1 -1
- package/dist/permission-suite.js +27 -0
- package/dist/permission-suite.js.map +1 -1
- package/dist/schedule-suite.d.ts +5 -4
- package/dist/schedule-suite.d.ts.map +1 -1
- package/dist/schedule-suite.js +12 -12
- package/dist/schedule-suite.js.map +1 -1
- package/dist/scope-host-suite.d.ts.map +1 -1
- package/dist/scope-host-suite.js +50 -11
- package/dist/scope-host-suite.js.map +1 -1
- package/dist/scope-repoint-suite.d.ts.map +1 -1
- package/dist/scope-repoint-suite.js +400 -0
- package/dist/scope-repoint-suite.js.map +1 -1
- package/dist/system-switch-suite.d.ts.map +1 -1
- package/dist/system-switch-suite.js +11 -8
- package/dist/system-switch-suite.js.map +1 -1
- package/package.json +3 -3
package/dist/scope-host-suite.js
CHANGED
|
@@ -1516,6 +1516,35 @@ export function scopeHostContractSuite(adapterName, makeFixture, opts = {}) {
|
|
|
1516
1516
|
// `poison-a` failed and is backed off: an error on the row, but a retry still due.
|
|
1517
1517
|
expect(page.entries.some((d) => d.consumer === 'executor:flaky-effector')).toBe(false);
|
|
1518
1518
|
});
|
|
1519
|
+
it('replays a declared lifecycle over the outbox through the platform verb (#1744)', async () => {
|
|
1520
|
+
// `readLifecycleFlow`'s own suite pins the replay over a hand-built outbox; this
|
|
1521
|
+
// proves the wiring — real emits, on both adapters, read back through `lifecycleFlow`.
|
|
1522
|
+
const stub = await host.getScope(alice, t1, s1);
|
|
1523
|
+
const since = new Date(Date.now() - 60_000).toISOString();
|
|
1524
|
+
await stub.invoke('test/move', { entityId: 'l1', state: 'draft' });
|
|
1525
|
+
await stub.invoke('test/move', { entityId: 'l1', state: 'live' });
|
|
1526
|
+
// No state in the payload: the declared edge says where it went.
|
|
1527
|
+
await stub.invoke('test/move', { entityId: 'l1' });
|
|
1528
|
+
const flow = await host.admin.lifecycleFlow(staff, t1, s1, {
|
|
1529
|
+
entityType: 'test-lifecycle',
|
|
1530
|
+
lifecycle: {
|
|
1531
|
+
field: 'state',
|
|
1532
|
+
initial: 'draft',
|
|
1533
|
+
states: {
|
|
1534
|
+
draft: { on: { 'test/move': 'live' } },
|
|
1535
|
+
live: { on: { 'test/move': 'done' } },
|
|
1536
|
+
done: { terminal: true },
|
|
1537
|
+
},
|
|
1538
|
+
},
|
|
1539
|
+
since,
|
|
1540
|
+
until: new Date(Date.now() + 60_000).toISOString(),
|
|
1541
|
+
});
|
|
1542
|
+
expect(flow.edges.find((e) => e.from === 'draft' && e.to === 'live').count).toBe(1);
|
|
1543
|
+
expect(flow.edges.find((e) => e.from === 'live' && e.to === 'done').count).toBe(1);
|
|
1544
|
+
expect(flow.states.find((s) => s.state === 'done').current).toBe(1);
|
|
1545
|
+
expect(flow.observation).toMatchObject({ entities: 1, events: 3, inferred: 1, complete: true });
|
|
1546
|
+
expect(flow.totals.finished).toBe(1);
|
|
1547
|
+
});
|
|
1519
1548
|
// -- scope data introspection: the §5.4 admin-query RPC --------------------
|
|
1520
1549
|
//
|
|
1521
1550
|
// A read-only window into a scope's OWN database (the console/dashboard Data
|
|
@@ -2166,10 +2195,10 @@ export function scopeHostContractSuite(adapterName, makeFixture, opts = {}) {
|
|
|
2166
2195
|
const dump = await host.admin.exportScope(staff, t1, s1);
|
|
2167
2196
|
// Doctor the dump into one captured before the `operation` column existed:
|
|
2168
2197
|
// the DDL loses the column and every row loses that cell — exactly what a
|
|
2169
|
-
// dump exported by an older platform carries. The
|
|
2170
|
-
//
|
|
2171
|
-
//
|
|
2172
|
-
//
|
|
2198
|
+
// dump exported by an older platform carries. The restore builds the outbox
|
|
2199
|
+
// from the kernel's DDL, not the dump's (#1883), and inserts the rows by
|
|
2200
|
+
// column name, so the missing cell reads NULL and the emit below still has
|
|
2201
|
+
// its column.
|
|
2173
2202
|
const doctored = dump.tables.map((t) => {
|
|
2174
2203
|
if (t.name !== '_substrat_outbox')
|
|
2175
2204
|
return t;
|
|
@@ -2289,6 +2318,14 @@ export function scopeHostContractSuite(adapterName, makeFixture, opts = {}) {
|
|
|
2289
2318
|
{ name: 'MARKER', ddl: 'CREATE TABLE MARKER (id TEXT)', columns: ['id'], rows: [] },
|
|
2290
2319
|
])).rejects.toThrow(/listed twice/);
|
|
2291
2320
|
});
|
|
2321
|
+
// A column listed twice is the same shape one level down: the row insert names it twice,
|
|
2322
|
+
// and which of the two cells lands is SQLite's choice, not the dump's. Case-folded, as
|
|
2323
|
+
// SQLite resolves column names that way too (#1883 review).
|
|
2324
|
+
it('refuses a column listed twice in one table, including differing only in case', async () => {
|
|
2325
|
+
await expect(importForged([
|
|
2326
|
+
{ name: 'marker', ddl: 'CREATE TABLE marker (id TEXT, note TEXT)', columns: ['id', 'note', 'ID'], rows: [] },
|
|
2327
|
+
])).rejects.toThrow(/column "ID" in table "marker" is listed twice/);
|
|
2328
|
+
});
|
|
2292
2329
|
// Non-vacuous: proves the checks do not simply reject everything, and that a
|
|
2293
2330
|
// `;` inside a string literal is not read as a statement boundary — a DEFAULT
|
|
2294
2331
|
// of `'a;b'` is legal SQL, and a `split(';')` would refuse it.
|
|
@@ -2350,6 +2387,8 @@ export function scopeHostContractSuite(adapterName, makeFixture, opts = {}) {
|
|
|
2350
2387
|
expect(ids).toContain(t2);
|
|
2351
2388
|
});
|
|
2352
2389
|
it('restores: a directory diverged past the copy is rewound, and still serves', async () => {
|
|
2390
|
+
const ownRestores = { actor: staff, action: 'restoreDirectory' };
|
|
2391
|
+
const restoresInCopy = (await host.admin.auditLog(staff, ownRestores)).length;
|
|
2353
2392
|
const backup = await host.admin.exportDirectory(staff);
|
|
2354
2393
|
// Diverge past the copy — a tenant that did not exist when it was taken.
|
|
2355
2394
|
const ghost = tenantId.parse(ulid());
|
|
@@ -2375,13 +2414,13 @@ export function scopeHostContractSuite(adapterName, makeFixture, opts = {}) {
|
|
|
2375
2414
|
// The restore is audited, in the log it just replaced: the entry after a
|
|
2376
2415
|
// restored history is the restore itself, so the seam is legible.
|
|
2377
2416
|
//
|
|
2378
|
-
//
|
|
2379
|
-
//
|
|
2380
|
-
//
|
|
2381
|
-
//
|
|
2382
|
-
//
|
|
2383
|
-
|
|
2384
|
-
expect(
|
|
2417
|
+
// Filtered to THIS suite's restores and read as a delta, never as a window over the
|
|
2418
|
+
// whole log: the log reads oldest-first and is the whole directory's, so a window
|
|
2419
|
+
// stops reaching the entry once enough other rows precede it. A 50-row window did
|
|
2420
|
+
// when the suite's own rows grew (#1334), and a 500-row one did when other test
|
|
2421
|
+
// files sharing the directory ran first (#1899). The copy carries the restores it
|
|
2422
|
+
// had seen, so one more than it held is exactly this one.
|
|
2423
|
+
expect((await host.admin.auditLog(staff, ownRestores)).length).toBe(restoresInCopy + 1);
|
|
2385
2424
|
});
|
|
2386
2425
|
// A directory dump is untrusted input exactly as a scope dump is (#1143), and
|
|
2387
2426
|
// both adapters refuse it with the same words. The DO path always judged it;
|