1212 * and no other test sees until it lands: a `cut-rc` pass in pre mode makes
1313 * the CLI `X.Y.Z-rc.N`, and that whole string — prerelease tail included — is
1414 * the pin. The CLI reads its version from its own `package.json` once and
15- * caches it, so the module graph is re-imported under a planted manifest read.
15+ * caches it, so this file first imports the commands under a planted manifest read.
1616 * The in-repo placement is the control: it keeps `workspace:*`.
1717 */
1818
19- import { describe , it , expect , vi , beforeAll , afterAll } from 'vitest' ;
19+ import { describe , it , expect , vi } from 'vitest' ;
2020import fs from 'fs' ;
2121import path from 'path' ;
2222import { fileURLToPath } from 'url' ;
@@ -25,12 +25,6 @@ const HERE = path.dirname(fileURLToPath(import.meta.url));
2525const CLI_MANIFEST = path . resolve ( HERE , '..' , 'package.json' ) ;
2626const PRERELEASE = '18.1.0-rc.2' ;
2727
28- type InitModule = typeof import ( '../src/commands/init.js' ) ;
29- type CreateModule = typeof import ( '../src/commands/create.js' ) ;
30-
31- let init : InitModule ;
32- let create : CreateModule ;
33-
3428/** Every `@objectstack/*` entry of a manifest, both dependency sections. */
3529function objectstackDeps ( pkg : {
3630 dependencies ?: Record < string , string > ;
@@ -41,28 +35,34 @@ function objectstackDeps(pkg: {
4135 ) ;
4236}
4337
44- beforeAll ( async ( ) => {
45- const realRead = fs . readFileSync ;
46- const spy = vi . spyOn ( fs , 'readFileSync' ) . mockImplementation ( ( ( file : unknown , ... rest : unknown [ ] ) =>
47- typeof file === 'string' && path . resolve ( file ) === CLI_MANIFEST
48- ? JSON . stringify ( { name : '@objectstack/cli' , version : PRERELEASE } )
49- : ( realRead as ( ...args : unknown [ ] ) => unknown ) ( file , ... rest ) ) as typeof fs . readFileSync ) ;
50- try {
51- vi . resetModules ( ) ;
52- init = await import ( '../src/commands/init.js' ) ;
53- create = await import ( '../src/commands/create .js' ) ;
54- // Read while the planted manifest is in place; the value is cached after.
55- expect ( init . getCliVersion ( ) ) . toBe ( PRERELEASE ) ;
56- } finally {
57- spy . mockRestore ( ) ;
58- }
59- } ) ;
60-
61- afterAll ( ( ) => {
62- vi . resetModules ( ) ;
63- } ) ;
38+ // The first import of the command modules happens HERE, under the planted
39+ // manifest read, at collection time: each test file gets its own module
40+ // registry, so no reset is needed, and module evaluation is not charged to a
41+ // hook's timeout.
42+ const realRead = fs . readFileSync ;
43+ const spy = vi . spyOn ( fs , 'readFileSync' ) . mockImplementation ( ( ( file : unknown , ...rest : unknown [ ] ) =>
44+ typeof file === 'string' && path . resolve ( file ) === CLI_MANIFEST
45+ ? JSON . stringify ( { name : '@objectstack/cli' , version : PRERELEASE } )
46+ : ( realRead as ( ... args : unknown [ ] ) => unknown ) ( file , ... rest ) ) as typeof fs . readFileSync ) ;
47+ let init : typeof import ( '../src/commands/init .js' ) ;
48+ let create : typeof import ( '../src/commands/create.js' ) ;
49+ let plantedVersion : string ;
50+ try {
51+ init = await import ( '../src/commands/init.js' ) ;
52+ create = await import ( '../src/commands/create.js' ) ;
53+ // Read while the planted manifest is in place; the value is cached after.
54+ plantedVersion = init . getCliVersion ( ) ;
55+ } finally {
56+ spy . mockRestore ( ) ;
57+ }
6458
6559describe ( 'a prerelease CLI pins scaffolded @objectstack/* deps exactly' , ( ) => {
60+ // Harness guard: without it, a manifest read that escaped the spy would
61+ // measure the checkout's own release version and prove nothing about tails.
62+ it ( 'reads the planted prerelease as the CLI version' , ( ) => {
63+ expect ( plantedVersion ) . toBe ( PRERELEASE ) ;
64+ } ) ;
65+
6666 it ( 'os init: every template, every @objectstack/* dep' , ( ) => {
6767 const keys = Object . keys ( init . TEMPLATES ) ;
6868 expect ( keys . length ) . toBeGreaterThan ( 0 ) ;
0 commit comments