@specific.dev/spectest 0.110.0 → 0.111.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/daemon.js CHANGED
@@ -2932,7 +2932,7 @@ async function bootstrapInner(prepared, identity) {
2932
2932
  let interactiveSetupCompleted = false;
2933
2933
  /**
2934
2934
  * Run a project setup hook. Normal `setup` runs before the shared warm
2935
- * snapshot; `setupInteractive` runs only after it, in a fresh user start.
2935
+ * snapshot; `interactive.seed` runs only after it, in a fresh user start.
2936
2936
  * Both use the same context and boot-log capture.
2937
2937
  *
2938
2938
  * Unlike test runs, this is NOT instrumented — no recorder, no event
@@ -2951,7 +2951,8 @@ async function runProjectSetup(hook = "setup") {
2951
2951
  }
2952
2952
  }
2953
2953
  async function runProjectSetupInner(hook) {
2954
- const setup = requireLoaded().project[hook];
2954
+ const project = requireLoaded().project;
2955
+ const setup = hook === "setup" ? project.setup : project.interactive?.seed;
2955
2956
  if (!setup || (hook === "setupInteractive" && interactiveSetupCompleted)) {
2956
2957
  return { ran: false, durationMs: 0 };
2957
2958
  }
@@ -5143,7 +5144,7 @@ export function harnessMethods(state) {
5143
5144
  capabilities: ["prepared-images-v1"],
5144
5145
  // Optional discovery: old SDKs omit this field and are never sent the
5145
5146
  // new method. Check the loaded project, including after warm restore.
5146
- setupInteractive: typeof loaded?.project.setupInteractive === "function",
5147
+ setupInteractive: typeof loaded?.project.interactive?.seed === "function",
5147
5148
  replayEnvironmentMode: true,
5148
5149
  }),
5149
5150
  // Live bootstrap progress, polled by the control plane during
package/dist/index.d.ts CHANGED
@@ -1627,21 +1627,24 @@ export interface Project<S extends ServicesMap = ServicesMap, F extends FakesMap
1627
1627
  /**
1628
1628
  * Prepare a new interactive environment, after normal setup and the shared
1629
1629
  * warm-template snapshot. Runs on both cold starts and warm restores from
1630
- * the dashboard or `spectest env start`, before the environment is ready.
1630
+ * the dashboard (seed checkbox on) or `spectest env start --seed`, before
1631
+ * the environment is ready. Skipped when seeding is not requested.
1631
1632
  * Never runs for tests, snapshot forks, or resuming a stopped environment.
1632
1633
  * Uses the same context as `setup`; throw to fail the start.
1633
1634
  */
1634
- setupInteractive?: ProjectSetupFn<S, F>;
1635
+ interactive?: {
1636
+ seed?: ProjectSetupFn<S, F>;
1637
+ };
1635
1638
  tests?: TestSuite<S, F>;
1636
1639
  }
1637
1640
  /**
1638
- * Context handed to the project-level `setup` and `setupInteractive` hooks: the full
1641
+ * Context handed to the project-level `setup` and `interactive.seed` hooks: the full
1639
1642
  * {@link SpectestContext}, minus only what a timeline gives a test
1640
1643
  * (testName, parent, browser/mobile/terminal). Everything a test can do
1641
1644
  * to the environment — exec, fetch, `svc`/`fakes` helpers, `poll`,
1642
1645
  * `dnsName`, `certificate`, `startService`, and project-file access via
1643
1646
  * `projectRoot`/`readProjectFile` — is available here too. Normal `setup`
1644
- * state is captured into the shared warm template; `setupInteractive`
1647
+ * state is captured into the shared warm template; `interactive.seed`
1645
1648
  * state belongs only to the new interactive environment.
1646
1649
  */
1647
1650
  export interface ProjectSetupContext<S extends ServicesMap = ServicesMap, F extends FakesMap = FakesMap> extends SpectestContext<S, F> {
@@ -1681,8 +1684,10 @@ export type ProjectSetupFn<S extends ServicesMap = ServicesMap, F extends FakesM
1681
1684
  export interface ProjectOpts<S extends ServicesMap = ServicesMap, F extends FakesMap = FakesMap> {
1682
1685
  /** Optional project-level setup. See `Project.setup`. */
1683
1686
  setup?: ProjectSetupFn<S, F>;
1684
- /** Optional interactive-only setup. See `Project.setupInteractive`. */
1685
- setupInteractive?: ProjectSetupFn<S, F>;
1687
+ /** Optional interactive-only setup. See `Project.interactive`. */
1688
+ interactive?: {
1689
+ seed?: ProjectSetupFn<S, F>;
1690
+ };
1686
1691
  /** Test cases for this project's suite. */
1687
1692
  tests?: TestCase<unknown, S, F>[];
1688
1693
  }
@@ -1736,7 +1741,7 @@ export interface DefinedEnvironment<S extends ServicesMap, F extends FakesMap =
1736
1741
  group<P = undefined>(name: string, opts?: GroupOpts<P, S, F>): TestGroup<P, S, F>;
1737
1742
  /** Bundle this environment with a test suite into the project default
1738
1743
  * export. Pass tests as a plain array for the common case, or an
1739
- * options bag to attach `setup` or `setupInteractive`. (Fakes are declared on
1744
+ * options bag to attach `setup` or `interactive.seed`. (Fakes are declared on
1740
1745
  * `defineEnvironment`, not here.) */
1741
1746
  project(tests?: TestCase<unknown, S, F>[]): Project<S, F>;
1742
1747
  project(opts: ProjectOpts<S, F>): Project<S, F>;
package/dist/index.js CHANGED
@@ -484,8 +484,8 @@ export function defineEnvironment(input) {
484
484
  const proj = { environment: config };
485
485
  if (opts.setup)
486
486
  proj.setup = opts.setup;
487
- if (opts.setupInteractive)
488
- proj.setupInteractive = opts.setupInteractive;
487
+ if (opts.interactive)
488
+ proj.interactive = opts.interactive;
489
489
  if (fakes)
490
490
  proj.fakes = fakes;
491
491
  if (opts.tests && opts.tests.length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specific.dev/spectest",
3
- "version": "0.110.0",
3
+ "version": "0.111.0",
4
4
  "description": "Spectest SDK for defining test environments in TypeScript.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/daemon.ts CHANGED
@@ -3481,7 +3481,7 @@ let interactiveSetupCompleted = false;
3481
3481
 
3482
3482
  /**
3483
3483
  * Run a project setup hook. Normal `setup` runs before the shared warm
3484
- * snapshot; `setupInteractive` runs only after it, in a fresh user start.
3484
+ * snapshot; `interactive.seed` runs only after it, in a fresh user start.
3485
3485
  * Both use the same context and boot-log capture.
3486
3486
  *
3487
3487
  * Unlike test runs, this is NOT instrumented — no recorder, no event
@@ -3500,7 +3500,8 @@ async function runProjectSetup(hook: "setup" | "setupInteractive" = "setup"): Pr
3500
3500
  }
3501
3501
 
3502
3502
  async function runProjectSetupInner(hook: "setup" | "setupInteractive"): Promise<ProjectSetupResult> {
3503
- const setup = requireLoaded().project[hook];
3503
+ const project = requireLoaded().project;
3504
+ const setup = hook === "setup" ? project.setup : project.interactive?.seed;
3504
3505
  if (!setup || (hook === "setupInteractive" && interactiveSetupCompleted)) {
3505
3506
  return { ran: false, durationMs: 0 };
3506
3507
  }
@@ -6161,7 +6162,7 @@ export function harnessMethods(state: RouteState): MethodTable {
6161
6162
  capabilities: ["prepared-images-v1"],
6162
6163
  // Optional discovery: old SDKs omit this field and are never sent the
6163
6164
  // new method. Check the loaded project, including after warm restore.
6164
- setupInteractive: typeof loaded?.project.setupInteractive === "function",
6165
+ setupInteractive: typeof loaded?.project.interactive?.seed === "function",
6165
6166
  replayEnvironmentMode: true,
6166
6167
  }),
6167
6168
 
package/src/index.ts CHANGED
@@ -2380,22 +2380,23 @@ export interface Project<
2380
2380
  /**
2381
2381
  * Prepare a new interactive environment, after normal setup and the shared
2382
2382
  * warm-template snapshot. Runs on both cold starts and warm restores from
2383
- * the dashboard or `spectest env start`, before the environment is ready.
2383
+ * the dashboard (seed checkbox on) or `spectest env start --seed`, before
2384
+ * the environment is ready. Skipped when seeding is not requested.
2384
2385
  * Never runs for tests, snapshot forks, or resuming a stopped environment.
2385
2386
  * Uses the same context as `setup`; throw to fail the start.
2386
2387
  */
2387
- setupInteractive?: ProjectSetupFn<S, F>;
2388
+ interactive?: { seed?: ProjectSetupFn<S, F> };
2388
2389
  tests?: TestSuite<S, F>;
2389
2390
  }
2390
2391
 
2391
2392
  /**
2392
- * Context handed to the project-level `setup` and `setupInteractive` hooks: the full
2393
+ * Context handed to the project-level `setup` and `interactive.seed` hooks: the full
2393
2394
  * {@link SpectestContext}, minus only what a timeline gives a test
2394
2395
  * (testName, parent, browser/mobile/terminal). Everything a test can do
2395
2396
  * to the environment — exec, fetch, `svc`/`fakes` helpers, `poll`,
2396
2397
  * `dnsName`, `certificate`, `startService`, and project-file access via
2397
2398
  * `projectRoot`/`readProjectFile` — is available here too. Normal `setup`
2398
- * state is captured into the shared warm template; `setupInteractive`
2399
+ * state is captured into the shared warm template; `interactive.seed`
2399
2400
  * state belongs only to the new interactive environment.
2400
2401
  */
2401
2402
  export interface ProjectSetupContext<
@@ -2445,8 +2446,8 @@ export interface ProjectOpts<
2445
2446
  > {
2446
2447
  /** Optional project-level setup. See `Project.setup`. */
2447
2448
  setup?: ProjectSetupFn<S, F>;
2448
- /** Optional interactive-only setup. See `Project.setupInteractive`. */
2449
- setupInteractive?: ProjectSetupFn<S, F>;
2449
+ /** Optional interactive-only setup. See `Project.interactive`. */
2450
+ interactive?: { seed?: ProjectSetupFn<S, F> };
2450
2451
  /** Test cases for this project's suite. */
2451
2452
  tests?: TestCase<unknown, S, F>[];
2452
2453
  }
@@ -2511,7 +2512,7 @@ export interface DefinedEnvironment<
2511
2512
  ): TestGroup<P, S, F>;
2512
2513
  /** Bundle this environment with a test suite into the project default
2513
2514
  * export. Pass tests as a plain array for the common case, or an
2514
- * options bag to attach `setup` or `setupInteractive`. (Fakes are declared on
2515
+ * options bag to attach `setup` or `interactive.seed`. (Fakes are declared on
2515
2516
  * `defineEnvironment`, not here.) */
2516
2517
  project(tests?: TestCase<unknown, S, F>[]): Project<S, F>;
2517
2518
  project(opts: ProjectOpts<S, F>): Project<S, F>;
@@ -2663,7 +2664,7 @@ export function defineEnvironment<
2663
2664
  : (arg ?? {});
2664
2665
  const proj: Project<S, F> = { environment: config };
2665
2666
  if (opts.setup) proj.setup = opts.setup;
2666
- if (opts.setupInteractive) proj.setupInteractive = opts.setupInteractive;
2667
+ if (opts.interactive) proj.interactive = opts.interactive;
2667
2668
  if (fakes) proj.fakes = fakes;
2668
2669
  if (opts.tests && opts.tests.length > 0) {
2669
2670
  // Explicit suite (single-file / legacy layout): the tests are listed
@@ -22,7 +22,7 @@ for (const withHook of [false, true]) {
22
22
  }});
23
23
  export default env.project({
24
24
  setup: () => { calls.push("baseline"); },
25
- ${withHook ? `setupInteractive: async (ctx) => {
25
+ ${withHook ? `interactive: { seed: async (ctx) => {
26
26
  calls.push("interactive");
27
27
  console.log("seeding demo data");
28
28
  await globalThis.seedGate;
@@ -35,7 +35,7 @@ for (const withHook of [false, true]) {
35
35
  if (typeof result.exitCode !== "number" || !result.stdout.includes("seed demo")) {
36
36
  throw new Error("exec result not plain: " + JSON.stringify(result));
37
37
  }
38
- },` : ""}
38
+ } },` : ""}
39
39
  });
40
40
  `);
41
41
  const script = `