@sanity/cli-test 0.2.6 → 0.3.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.
@@ -30,14 +30,11 @@ import { createTestToken } from './createTestToken.js';
30
30
  createTestToken(options.token);
31
31
  }
32
32
  // Auto-convert paths in projectRoot to platform-appropriate format
33
- let projectRoot = options.projectRoot;
34
- if (projectRoot) {
35
- projectRoot = {
36
- ...projectRoot,
37
- directory: convertToSystemPath(projectRoot.directory),
38
- path: convertToSystemPath(projectRoot.path)
39
- };
40
- }
33
+ const projectRoot = options.projectRoot ? {
34
+ ...options.projectRoot,
35
+ directory: convertToSystemPath(options.projectRoot.directory),
36
+ path: convertToSystemPath(options.projectRoot.path)
37
+ } : undefined;
41
38
  // Create a subclass that overrides methods when mocks are provided
42
39
  // Note: we use @ts-expect-error because TypeScript can't properly infer
43
40
  // the relationship between the generic CommandClass and SanityCommand
@@ -56,8 +53,8 @@ import { createTestToken } from './createTestToken.js';
56
53
  if (options.cliConfigError && 'name' in options.cliConfigError && options.cliConfigError.name === 'ProjectRootNotFoundError') {
57
54
  return Promise.reject(options.cliConfigError);
58
55
  }
59
- if (options.projectRoot) {
60
- return Promise.resolve(options.projectRoot);
56
+ if (projectRoot) {
57
+ return Promise.resolve(projectRoot);
61
58
  }
62
59
  return super.getProjectRoot();
63
60
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/test/mockSanityCommand.ts"],"sourcesContent":["import {type Command} from '@oclif/core'\nimport {type CliConfig, type ProjectRootResult, SanityCommand} from '@sanity/cli-core'\n\nimport {convertToSystemPath} from '../utils/paths.js'\nimport {createTestToken} from './createTestToken.js'\n\n/**\n * @public\n */\nexport interface MockSanityCommandOptions {\n /**\n * Mock CLI config (required if command uses getCliConfig or getProjectId)\n */\n cliConfig?: CliConfig\n /**\n * When provided, getCliConfig() will throw this error instead of returning a config.\n * Useful for simulating running outside a project directory.\n */\n cliConfigError?: Error\n /**\n * Mock whether the terminal is interactive (used by isUnattended)\n */\n isInteractive?: boolean\n /**\n * Mock project root result (required if command uses getProjectRoot)\n */\n projectRoot?: ProjectRootResult\n /**\n * Mock authentication token (passed to API clients, bypasses getCliToken)\n */\n token?: string\n}\n\n/**\n * Creates a testable subclass of a command with mocked SanityCommand dependencies.\n *\n * @public\n *\n * @example\n * ```ts\n * // Basic config mocking\n * const TestAdd = mockSanityCommand(Add, {\n * cliConfig: { api: { projectId: 'test-project' } }\n * })\n *\n * // With mock API client\n * const mockClient = {\n * getDocument: vi.fn().mockResolvedValue({ _id: 'doc1', title: 'Test' }),\n * fetch: vi.fn().mockResolvedValue([]),\n * }\n * const TestGet = mockSanityCommand(GetDocumentCommand, {\n * cliConfig: { api: { projectId: 'test-project', dataset: 'production' } },\n * projectApiClient: mockClient,\n * })\n *\n * const {stdout} = await testCommand(TestGet, ['doc1'])\n * expect(mockClient.getDocument).toHaveBeenCalledWith('doc1')\n * ```\n */\nexport function mockSanityCommand<T extends typeof SanityCommand<typeof Command>>(\n CommandClass: T,\n options: MockSanityCommandOptions = {},\n): T {\n if (options.token) {\n createTestToken(options.token)\n }\n\n // Auto-convert paths in projectRoot to platform-appropriate format\n let projectRoot = options.projectRoot\n if (projectRoot) {\n projectRoot = {\n ...projectRoot,\n directory: convertToSystemPath(projectRoot.directory),\n path: convertToSystemPath(projectRoot.path),\n }\n }\n\n // Create a subclass that overrides methods when mocks are provided\n // Note: we use @ts-expect-error because TypeScript can't properly infer\n // the relationship between the generic CommandClass and SanityCommand\n // @ts-expect-error - TypeScript struggles with abstract class subclassing\n class MockedCommand extends CommandClass {\n protected getCliConfig(): Promise<CliConfig> {\n if (options.cliConfigError) {\n return Promise.reject(options.cliConfigError)\n }\n if (options.cliConfig) {\n return Promise.resolve(options.cliConfig)\n }\n return super.getCliConfig()\n }\n\n protected getProjectRoot(): Promise<ProjectRootResult> {\n if (\n options.cliConfigError &&\n 'name' in options.cliConfigError &&\n options.cliConfigError.name === 'ProjectRootNotFoundError'\n ) {\n return Promise.reject(options.cliConfigError)\n }\n if (options.projectRoot) {\n return Promise.resolve(options.projectRoot)\n }\n return super.getProjectRoot()\n }\n\n protected resolveIsInteractive(): boolean {\n if (options.isInteractive !== undefined) {\n return options.isInteractive\n }\n return super.resolveIsInteractive()\n }\n }\n\n return MockedCommand as T\n}\n"],"names":["convertToSystemPath","createTestToken","mockSanityCommand","CommandClass","options","token","projectRoot","directory","path","MockedCommand","getCliConfig","cliConfigError","Promise","reject","cliConfig","resolve","getProjectRoot","name","resolveIsInteractive","isInteractive","undefined"],"mappings":"AAGA,SAAQA,mBAAmB,QAAO,oBAAmB;AACrD,SAAQC,eAAe,QAAO,uBAAsB;AA6BpD;;;;;;;;;;;;;;;;;;;;;;;;;CAyBC,GACD,OAAO,SAASC,kBACdC,YAAe,EACfC,UAAoC,CAAC,CAAC;IAEtC,IAAIA,QAAQC,KAAK,EAAE;QACjBJ,gBAAgBG,QAAQC,KAAK;IAC/B;IAEA,mEAAmE;IACnE,IAAIC,cAAcF,QAAQE,WAAW;IACrC,IAAIA,aAAa;QACfA,cAAc;YACZ,GAAGA,WAAW;YACdC,WAAWP,oBAAoBM,YAAYC,SAAS;YACpDC,MAAMR,oBAAoBM,YAAYE,IAAI;QAC5C;IACF;IAEA,mEAAmE;IACnE,wEAAwE;IACxE,sEAAsE;IACtE,0EAA0E;IAC1E,MAAMC,sBAAsBN;QAChBO,eAAmC;YAC3C,IAAIN,QAAQO,cAAc,EAAE;gBAC1B,OAAOC,QAAQC,MAAM,CAACT,QAAQO,cAAc;YAC9C;YACA,IAAIP,QAAQU,SAAS,EAAE;gBACrB,OAAOF,QAAQG,OAAO,CAACX,QAAQU,SAAS;YAC1C;YACA,OAAO,KAAK,CAACJ;QACf;QAEUM,iBAA6C;YACrD,IACEZ,QAAQO,cAAc,IACtB,UAAUP,QAAQO,cAAc,IAChCP,QAAQO,cAAc,CAACM,IAAI,KAAK,4BAChC;gBACA,OAAOL,QAAQC,MAAM,CAACT,QAAQO,cAAc;YAC9C;YACA,IAAIP,QAAQE,WAAW,EAAE;gBACvB,OAAOM,QAAQG,OAAO,CAACX,QAAQE,WAAW;YAC5C;YACA,OAAO,KAAK,CAACU;QACf;QAEUE,uBAAgC;YACxC,IAAId,QAAQe,aAAa,KAAKC,WAAW;gBACvC,OAAOhB,QAAQe,aAAa;YAC9B;YACA,OAAO,KAAK,CAACD;QACf;IACF;IAEA,OAAOT;AACT"}
1
+ {"version":3,"sources":["../../src/test/mockSanityCommand.ts"],"sourcesContent":["import {type Command} from '@oclif/core'\nimport {type CliConfig, type ProjectRootResult, SanityCommand} from '@sanity/cli-core'\n\nimport {convertToSystemPath} from '../utils/paths.js'\nimport {createTestToken} from './createTestToken.js'\n\n/**\n * @public\n */\nexport interface MockSanityCommandOptions {\n /**\n * Mock CLI config (required if command uses getCliConfig or getProjectId)\n */\n cliConfig?: CliConfig\n /**\n * When provided, getCliConfig() will throw this error instead of returning a config.\n * Useful for simulating running outside a project directory.\n */\n cliConfigError?: Error\n /**\n * Mock whether the terminal is interactive (used by isUnattended)\n */\n isInteractive?: boolean\n /**\n * Mock project root result (required if command uses getProjectRoot)\n */\n projectRoot?: ProjectRootResult\n /**\n * Mock authentication token (passed to API clients, bypasses getCliToken)\n */\n token?: string\n}\n\n/**\n * Creates a testable subclass of a command with mocked SanityCommand dependencies.\n *\n * @public\n *\n * @example\n * ```ts\n * // Basic config mocking\n * const TestAdd = mockSanityCommand(Add, {\n * cliConfig: { api: { projectId: 'test-project' } }\n * })\n *\n * // With mock API client\n * const mockClient = {\n * getDocument: vi.fn().mockResolvedValue({ _id: 'doc1', title: 'Test' }),\n * fetch: vi.fn().mockResolvedValue([]),\n * }\n * const TestGet = mockSanityCommand(GetDocumentCommand, {\n * cliConfig: { api: { projectId: 'test-project', dataset: 'production' } },\n * projectApiClient: mockClient,\n * })\n *\n * const {stdout} = await testCommand(TestGet, ['doc1'])\n * expect(mockClient.getDocument).toHaveBeenCalledWith('doc1')\n * ```\n */\nexport function mockSanityCommand<T extends typeof SanityCommand<typeof Command>>(\n CommandClass: T,\n options: MockSanityCommandOptions = {},\n): T {\n if (options.token) {\n createTestToken(options.token)\n }\n\n // Auto-convert paths in projectRoot to platform-appropriate format\n const projectRoot = options.projectRoot\n ? {\n ...options.projectRoot,\n directory: convertToSystemPath(options.projectRoot.directory),\n path: convertToSystemPath(options.projectRoot.path),\n }\n : undefined\n\n // Create a subclass that overrides methods when mocks are provided\n // Note: we use @ts-expect-error because TypeScript can't properly infer\n // the relationship between the generic CommandClass and SanityCommand\n // @ts-expect-error - TypeScript struggles with abstract class subclassing\n class MockedCommand extends CommandClass {\n protected getCliConfig(): Promise<CliConfig> {\n if (options.cliConfigError) {\n return Promise.reject(options.cliConfigError)\n }\n if (options.cliConfig) {\n return Promise.resolve(options.cliConfig)\n }\n return super.getCliConfig()\n }\n\n protected getProjectRoot(): Promise<ProjectRootResult> {\n if (\n options.cliConfigError &&\n 'name' in options.cliConfigError &&\n options.cliConfigError.name === 'ProjectRootNotFoundError'\n ) {\n return Promise.reject(options.cliConfigError)\n }\n if (projectRoot) {\n return Promise.resolve(projectRoot)\n }\n return super.getProjectRoot()\n }\n\n protected resolveIsInteractive(): boolean {\n if (options.isInteractive !== undefined) {\n return options.isInteractive\n }\n return super.resolveIsInteractive()\n }\n }\n\n return MockedCommand as T\n}\n"],"names":["convertToSystemPath","createTestToken","mockSanityCommand","CommandClass","options","token","projectRoot","directory","path","undefined","MockedCommand","getCliConfig","cliConfigError","Promise","reject","cliConfig","resolve","getProjectRoot","name","resolveIsInteractive","isInteractive"],"mappings":"AAGA,SAAQA,mBAAmB,QAAO,oBAAmB;AACrD,SAAQC,eAAe,QAAO,uBAAsB;AA6BpD;;;;;;;;;;;;;;;;;;;;;;;;;CAyBC,GACD,OAAO,SAASC,kBACdC,YAAe,EACfC,UAAoC,CAAC,CAAC;IAEtC,IAAIA,QAAQC,KAAK,EAAE;QACjBJ,gBAAgBG,QAAQC,KAAK;IAC/B;IAEA,mEAAmE;IACnE,MAAMC,cAAcF,QAAQE,WAAW,GACnC;QACE,GAAGF,QAAQE,WAAW;QACtBC,WAAWP,oBAAoBI,QAAQE,WAAW,CAACC,SAAS;QAC5DC,MAAMR,oBAAoBI,QAAQE,WAAW,CAACE,IAAI;IACpD,IACAC;IAEJ,mEAAmE;IACnE,wEAAwE;IACxE,sEAAsE;IACtE,0EAA0E;IAC1E,MAAMC,sBAAsBP;QAChBQ,eAAmC;YAC3C,IAAIP,QAAQQ,cAAc,EAAE;gBAC1B,OAAOC,QAAQC,MAAM,CAACV,QAAQQ,cAAc;YAC9C;YACA,IAAIR,QAAQW,SAAS,EAAE;gBACrB,OAAOF,QAAQG,OAAO,CAACZ,QAAQW,SAAS;YAC1C;YACA,OAAO,KAAK,CAACJ;QACf;QAEUM,iBAA6C;YACrD,IACEb,QAAQQ,cAAc,IACtB,UAAUR,QAAQQ,cAAc,IAChCR,QAAQQ,cAAc,CAACM,IAAI,KAAK,4BAChC;gBACA,OAAOL,QAAQC,MAAM,CAACV,QAAQQ,cAAc;YAC9C;YACA,IAAIN,aAAa;gBACf,OAAOO,QAAQG,OAAO,CAACV;YACzB;YACA,OAAO,KAAK,CAACW;QACf;QAEUE,uBAAgC;YACxC,IAAIf,QAAQgB,aAAa,KAAKX,WAAW;gBACvC,OAAOL,QAAQgB,aAAa;YAC9B;YACA,OAAO,KAAK,CAACD;QACf;IACF;IAEA,OAAOT;AACT"}
@@ -105,7 +105,9 @@ async function getAdditionalFixturePaths(fixtures) {
105
105
  const execError = error;
106
106
  spinner.fail('Failed to install dependencies');
107
107
  console.error(execError.stderr || execError.stdout || execError.message);
108
- throw new Error(`Error installing dependencies in ${toPath}: ${execError.stderr || execError.stdout || execError.message}`);
108
+ throw new Error(`Error installing dependencies in ${toPath}: ${execError.stderr || execError.stdout || execError.message}`, {
109
+ cause: error
110
+ });
109
111
  }
110
112
  }
111
113
  spinner.succeed('Test environment initialized');
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/test/setupFixtures.ts"],"sourcesContent":["import {exec as execNode} from 'node:child_process'\nimport {readFile, rm, writeFile} from 'node:fs/promises'\nimport {basename, join} from 'node:path'\nimport {promisify} from 'node:util'\n\nimport ora from 'ora'\nimport {glob} from 'tinyglobby'\nimport {type TestProject} from 'vitest/node'\n\nimport {fileExists} from '../utils/fileExists.js'\nimport {getFixturesPath, getTempPath} from '../utils/paths.js'\nimport {DEFAULT_FIXTURES} from './constants.js'\nimport {testCopyDirectory} from './testFixture.js'\n\nconst exec = promisify(execNode)\n\n/**\n * Options for setupTestFixtures\n *\n * @public\n */\nexport interface SetupTestFixturesOptions {\n /**\n * Glob patterns for additional fixture directories to set up.\n *\n * Each pattern is matched against directories in the current working directory.\n * Only directories containing a `package.json` file are included.\n *\n * @example\n * ```typescript\n * ['fixtures/*', 'dev/*']\n * ```\n */\n additionalFixtures?: string[]\n\n /**\n * Custom temp directory path. Defaults to process.cwd()/tmp\n */\n tempDir?: string\n}\n\nasync function getAdditionalFixturePaths(fixtures: string[]): Promise<FixtureDetails[]> {\n const paths = await glob(fixtures, {\n absolute: true,\n ignore: ['**/node_modules/**', '**/dist/**'],\n onlyDirectories: true,\n })\n\n const additionalFixtures: FixtureDetails[] = []\n\n for (const path of paths) {\n if (await fileExists(join(`${path}/package.json`))) {\n additionalFixtures.push({\n fixture: basename(path),\n fromPath: path,\n includeDist: false,\n })\n }\n }\n\n return additionalFixtures\n}\n\ninterface FixtureDetails {\n fixture: string\n fromPath: string\n includeDist: boolean\n}\n\n/**\n * Global setup function for initializing test fixtures.\n *\n * Copies fixtures from the bundled location to a temp directory\n * and installs dependencies.\n *\n * Note: Fixtures are NOT built during setup. Tests that need built\n * fixtures should build them as part of the test.\n *\n * This function is designed to be used with vitest globalSetup.\n *\n * @public\n *\n * @param options - Configuration options\n * @example\n * ```typescript\n * // In vitest.config.ts\n * export default defineConfig({\n * test: {\n * globalSetup: ['@sanity/cli-test/vitest']\n * }\n * })\n * ```\n */\nexport async function setup(_: TestProject, options: SetupTestFixturesOptions = {}): Promise<void> {\n const {additionalFixtures, tempDir} = options\n\n const spinner = ora({\n // Without this, the watch mode input is discarded\n discardStdin: false,\n text: 'Initializing test environment...',\n }).start()\n\n try {\n const fixturesDir = getFixturesPath()\n const tempDirectory = getTempPath(tempDir)\n\n const allFixturePaths: FixtureDetails[] = []\n\n // Add the default fixtures\n for (const [fixture, options] of Object.entries(DEFAULT_FIXTURES)) {\n allFixturePaths.push({\n fixture,\n fromPath: join(fixturesDir, fixture),\n includeDist: 'includeDist' in options && options.includeDist ? options.includeDist : false,\n })\n }\n\n // Add the additional fixtures\n if (additionalFixtures && additionalFixtures.length > 0) {\n const additionalFixturePaths = await getAdditionalFixturePaths(additionalFixtures)\n\n if (additionalFixturePaths.length > 0) {\n allFixturePaths.push(...additionalFixturePaths)\n } else {\n spinner.warn(\n `No additional fixtures found, check the glob pattern: ${additionalFixtures.join(', ')}`,\n )\n }\n }\n\n for (const {fixture, fromPath, includeDist} of allFixturePaths) {\n const toPath = join(tempDirectory, `fixture-${fixture}`)\n // Copy the fixture, excluding node_modules and dist\n await testCopyDirectory(fromPath, toPath, ['node_modules', ...(includeDist ? [] : ['dist'])])\n\n // Replace the package.json name with a temp name\n const packageJsonPath = join(toPath, 'package.json')\n const packageJson = await readFile(packageJsonPath, 'utf8')\n const packageJsonData = JSON.parse(packageJson)\n packageJsonData.name = `${packageJsonData.name}-test`\n await writeFile(packageJsonPath, JSON.stringify(packageJsonData, null, 2))\n\n // Run pnpm install --no-lockfile in the temp directory\n try {\n await exec(`pnpm install --prefer-offline --no-lockfile`, {\n cwd: toPath,\n })\n } catch (error) {\n const execError = error as {message: string; stderr?: string; stdout?: string}\n spinner.fail('Failed to install dependencies')\n console.error(execError.stderr || execError.stdout || execError.message)\n throw new Error(\n `Error installing dependencies in ${toPath}: ${execError.stderr || execError.stdout || execError.message}`,\n )\n }\n }\n\n spinner.succeed('Test environment initialized')\n } catch (error) {\n spinner.fail('Failed to initialize test environment')\n throw error\n }\n}\n\n/**\n * Options for teardownTestFixtures\n *\n * @public\n */\nexport interface TeardownTestFixturesOptions {\n /**\n * Custom temp directory path. Defaults to process.cwd()/tmp\n */\n tempDir?: string\n}\n\n/**\n * Teardown function to clean up test fixtures.\n *\n * Removes the temp directory created by setupTestFixtures.\n *\n * This function is designed to be used with vitest globalSetup.\n *\n * @public\n *\n * @param options - Configuration options\n */\nexport async function teardown(options: TeardownTestFixturesOptions = {}): Promise<void> {\n const {tempDir} = options\n const tempDirectory = getTempPath(tempDir)\n\n // Remove the tmp directory\n await rm(tempDirectory, {force: true, maxRetries: 3, recursive: true}).catch(() => {})\n}\n"],"names":["exec","execNode","readFile","rm","writeFile","basename","join","promisify","ora","glob","fileExists","getFixturesPath","getTempPath","DEFAULT_FIXTURES","testCopyDirectory","getAdditionalFixturePaths","fixtures","paths","absolute","ignore","onlyDirectories","additionalFixtures","path","push","fixture","fromPath","includeDist","setup","_","options","tempDir","spinner","discardStdin","text","start","fixturesDir","tempDirectory","allFixturePaths","Object","entries","length","additionalFixturePaths","warn","toPath","packageJsonPath","packageJson","packageJsonData","JSON","parse","name","stringify","cwd","error","execError","fail","console","stderr","stdout","message","Error","succeed","teardown","force","maxRetries","recursive","catch"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/test/setupFixtures.ts"],"sourcesContent":["import {exec as execNode} from 'node:child_process'\nimport {readFile, rm, writeFile} from 'node:fs/promises'\nimport {basename, join} from 'node:path'\nimport {promisify} from 'node:util'\n\nimport ora from 'ora'\nimport {glob} from 'tinyglobby'\nimport {type TestProject} from 'vitest/node'\n\nimport {fileExists} from '../utils/fileExists.js'\nimport {getFixturesPath, getTempPath} from '../utils/paths.js'\nimport {DEFAULT_FIXTURES} from './constants.js'\nimport {testCopyDirectory} from './testFixture.js'\n\nconst exec = promisify(execNode)\n\n/**\n * Options for setupTestFixtures\n *\n * @public\n */\nexport interface SetupTestFixturesOptions {\n /**\n * Glob patterns for additional fixture directories to set up.\n *\n * Each pattern is matched against directories in the current working directory.\n * Only directories containing a `package.json` file are included.\n *\n * @example\n * ```typescript\n * ['fixtures/*', 'dev/*']\n * ```\n */\n additionalFixtures?: string[]\n\n /**\n * Custom temp directory path. Defaults to process.cwd()/tmp\n */\n tempDir?: string\n}\n\nasync function getAdditionalFixturePaths(fixtures: string[]): Promise<FixtureDetails[]> {\n const paths = await glob(fixtures, {\n absolute: true,\n ignore: ['**/node_modules/**', '**/dist/**'],\n onlyDirectories: true,\n })\n\n const additionalFixtures: FixtureDetails[] = []\n\n for (const path of paths) {\n if (await fileExists(join(`${path}/package.json`))) {\n additionalFixtures.push({\n fixture: basename(path),\n fromPath: path,\n includeDist: false,\n })\n }\n }\n\n return additionalFixtures\n}\n\ninterface FixtureDetails {\n fixture: string\n fromPath: string\n includeDist: boolean\n}\n\n/**\n * Global setup function for initializing test fixtures.\n *\n * Copies fixtures from the bundled location to a temp directory\n * and installs dependencies.\n *\n * Note: Fixtures are NOT built during setup. Tests that need built\n * fixtures should build them as part of the test.\n *\n * This function is designed to be used with vitest globalSetup.\n *\n * @public\n *\n * @param options - Configuration options\n * @example\n * ```typescript\n * // In vitest.config.ts\n * export default defineConfig({\n * test: {\n * globalSetup: ['@sanity/cli-test/vitest']\n * }\n * })\n * ```\n */\nexport async function setup(_: TestProject, options: SetupTestFixturesOptions = {}): Promise<void> {\n const {additionalFixtures, tempDir} = options\n\n const spinner = ora({\n // Without this, the watch mode input is discarded\n discardStdin: false,\n text: 'Initializing test environment...',\n }).start()\n\n try {\n const fixturesDir = getFixturesPath()\n const tempDirectory = getTempPath(tempDir)\n\n const allFixturePaths: FixtureDetails[] = []\n\n // Add the default fixtures\n for (const [fixture, options] of Object.entries(DEFAULT_FIXTURES)) {\n allFixturePaths.push({\n fixture,\n fromPath: join(fixturesDir, fixture),\n includeDist: 'includeDist' in options && options.includeDist ? options.includeDist : false,\n })\n }\n\n // Add the additional fixtures\n if (additionalFixtures && additionalFixtures.length > 0) {\n const additionalFixturePaths = await getAdditionalFixturePaths(additionalFixtures)\n\n if (additionalFixturePaths.length > 0) {\n allFixturePaths.push(...additionalFixturePaths)\n } else {\n spinner.warn(\n `No additional fixtures found, check the glob pattern: ${additionalFixtures.join(', ')}`,\n )\n }\n }\n\n for (const {fixture, fromPath, includeDist} of allFixturePaths) {\n const toPath = join(tempDirectory, `fixture-${fixture}`)\n // Copy the fixture, excluding node_modules and dist\n await testCopyDirectory(fromPath, toPath, ['node_modules', ...(includeDist ? [] : ['dist'])])\n\n // Replace the package.json name with a temp name\n const packageJsonPath = join(toPath, 'package.json')\n const packageJson = await readFile(packageJsonPath, 'utf8')\n const packageJsonData = JSON.parse(packageJson)\n packageJsonData.name = `${packageJsonData.name}-test`\n await writeFile(packageJsonPath, JSON.stringify(packageJsonData, null, 2))\n\n // Run pnpm install --no-lockfile in the temp directory\n try {\n await exec(`pnpm install --prefer-offline --no-lockfile`, {\n cwd: toPath,\n })\n } catch (error) {\n const execError = error as {message: string; stderr?: string; stdout?: string}\n spinner.fail('Failed to install dependencies')\n console.error(execError.stderr || execError.stdout || execError.message)\n throw new Error(\n `Error installing dependencies in ${toPath}: ${execError.stderr || execError.stdout || execError.message}`,\n {cause: error},\n )\n }\n }\n\n spinner.succeed('Test environment initialized')\n } catch (error) {\n spinner.fail('Failed to initialize test environment')\n throw error\n }\n}\n\n/**\n * Options for teardownTestFixtures\n *\n * @public\n */\nexport interface TeardownTestFixturesOptions {\n /**\n * Custom temp directory path. Defaults to process.cwd()/tmp\n */\n tempDir?: string\n}\n\n/**\n * Teardown function to clean up test fixtures.\n *\n * Removes the temp directory created by setupTestFixtures.\n *\n * This function is designed to be used with vitest globalSetup.\n *\n * @public\n *\n * @param options - Configuration options\n */\nexport async function teardown(options: TeardownTestFixturesOptions = {}): Promise<void> {\n const {tempDir} = options\n const tempDirectory = getTempPath(tempDir)\n\n // Remove the tmp directory\n await rm(tempDirectory, {force: true, maxRetries: 3, recursive: true}).catch(() => {})\n}\n"],"names":["exec","execNode","readFile","rm","writeFile","basename","join","promisify","ora","glob","fileExists","getFixturesPath","getTempPath","DEFAULT_FIXTURES","testCopyDirectory","getAdditionalFixturePaths","fixtures","paths","absolute","ignore","onlyDirectories","additionalFixtures","path","push","fixture","fromPath","includeDist","setup","_","options","tempDir","spinner","discardStdin","text","start","fixturesDir","tempDirectory","allFixturePaths","Object","entries","length","additionalFixturePaths","warn","toPath","packageJsonPath","packageJson","packageJsonData","JSON","parse","name","stringify","cwd","error","execError","fail","console","stderr","stdout","message","Error","cause","succeed","teardown","force","maxRetries","recursive","catch"],"mappings":"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"}
@@ -16,11 +16,10 @@
16
16
  "@sanity/sdk-react": "^2.6.0",
17
17
  "react": "^19.2.3",
18
18
  "react-dom": "^19.2.3",
19
- "sanity": "^5.17.1"
19
+ "sanity": "^5.18.0"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@types/react": "^19.2.9",
23
- "sanity": "^5.17.1",
24
23
  "typescript": "^5.9.3"
25
24
  }
26
25
  }
@@ -9,6 +9,6 @@
9
9
  "@sanity/functions": "^1.2.0"
10
10
  },
11
11
  "devDependencies": {
12
- "sanity": "^5.17.1"
12
+ "sanity": "^5.18.0"
13
13
  }
14
14
  }
@@ -15,10 +15,10 @@
15
15
  "start": "sanity start"
16
16
  },
17
17
  "dependencies": {
18
- "@sanity/vision": "^5.17.1",
18
+ "@sanity/vision": "^5.18.0",
19
19
  "react": "^19.2.3",
20
20
  "react-dom": "^19.2.3",
21
- "sanity": "^5.17.1",
21
+ "sanity": "^5.18.0",
22
22
  "styled-components": "^6.3.8"
23
23
  },
24
24
  "devDependencies": {
@@ -12,10 +12,10 @@
12
12
  "deploy-graphql": "sanity graphql deploy"
13
13
  },
14
14
  "dependencies": {
15
- "@sanity/vision": "^5.17.1",
15
+ "@sanity/vision": "^5.18.0",
16
16
  "react": "^19.2.3",
17
17
  "react-dom": "^19.2.3",
18
- "sanity": "^5.17.1",
18
+ "sanity": "^5.18.0",
19
19
  "styled-components": "^6.3.8"
20
20
  },
21
21
  "devDependencies": {
@@ -15,10 +15,10 @@
15
15
  "start": "sanity start"
16
16
  },
17
17
  "dependencies": {
18
- "@sanity/vision": "^5.17.1",
18
+ "@sanity/vision": "^5.18.0",
19
19
  "react": "^19.2.3",
20
20
  "react-dom": "^19.2.3",
21
- "sanity": "^5.17.1",
21
+ "sanity": "^5.18.0",
22
22
  "styled-components": "^6.3.8"
23
23
  },
24
24
  "devDependencies": {
@@ -16,11 +16,10 @@
16
16
  "@sanity/sdk-react": "^2.6.0",
17
17
  "react": "^19.2.3",
18
18
  "react-dom": "^19.2.3",
19
- "sanity": "^5.17.1"
19
+ "sanity": "^5.18.0"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@types/react": "^19.2.9",
23
- "sanity": "^5.17.1",
24
23
  "typescript": "^5.9.3"
25
24
  }
26
25
  }
@@ -15,7 +15,7 @@
15
15
  "dependencies": {
16
16
  "react": "^19.2.3",
17
17
  "react-dom": "^19.2.3",
18
- "sanity": "^5.17.1",
18
+ "sanity": "^5.18.0",
19
19
  "styled-components": "^6.3.8"
20
20
  },
21
21
  "devDependencies": {
@@ -16,10 +16,10 @@
16
16
  },
17
17
  "dependencies": {
18
18
  "@sanity/code-input": "^7.0.6",
19
- "@sanity/vision": "^5.17.1",
19
+ "@sanity/vision": "^5.18.0",
20
20
  "react": "^19.2.3",
21
21
  "react-dom": "^19.2.3",
22
- "sanity": "^5.17.1",
22
+ "sanity": "^5.18.0",
23
23
  "sanity-plugin-media": "^4.1.1",
24
24
  "styled-components": "^6.3.8",
25
25
  "vite-tsconfig-paths": "^6.0.5"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/cli-test",
3
- "version": "0.2.6",
3
+ "version": "0.3.0",
4
4
  "description": "Sanity CLI test helpers and utilities",
5
5
  "keywords": [
6
6
  "cli",
@@ -43,7 +43,7 @@
43
43
  "access": "public"
44
44
  },
45
45
  "dependencies": {
46
- "@swc/core": "^1.15.18",
46
+ "@swc/core": "^1.15.21",
47
47
  "ansis": "^4.2.0",
48
48
  "esbuild": "^0.27.4",
49
49
  "nock": "^14.0.11",
@@ -52,28 +52,28 @@
52
52
  },
53
53
  "devDependencies": {
54
54
  "@eslint/compat": "^2.0.3",
55
- "@oclif/core": "^4.9.0",
56
- "@sanity/client": "^7.17.0",
57
- "@sanity/pkg-utils": "^10.4.11",
55
+ "@oclif/core": "^4.10.2",
56
+ "@sanity/client": "^7.20.0",
57
+ "@sanity/pkg-utils": "^10.4.13",
58
58
  "@swc/cli": "^0.8.0",
59
59
  "@types/node": "^20.19.37",
60
- "eslint": "^9.39.4",
60
+ "eslint": "^10.1.0",
61
61
  "publint": "^0.3.18",
62
62
  "rimraf": "^6.0.1",
63
63
  "tsx": "^4.21.0",
64
64
  "typescript": "^5.9.3",
65
- "vitest": "^4.1.0",
66
- "yaml": "^2.8.2",
65
+ "vitest": "^4.1.2",
66
+ "yaml": "^2.8.3",
67
67
  "@repo/package.config": "0.0.1",
68
- "@sanity/cli-core": "1.2.0",
69
- "@sanity/eslint-config-cli": "1.0.1",
70
- "@repo/tsconfig": "3.70.0"
68
+ "@repo/tsconfig": "3.70.0",
69
+ "@sanity/cli-core": "1.3.0",
70
+ "@sanity/eslint-config-cli": "1.1.0"
71
71
  },
72
72
  "peerDependencies": {
73
73
  "@oclif/core": "^4.0.0",
74
74
  "@sanity/client": "^7.0.0",
75
75
  "vitest": ">=3.0.0 <5.0.0",
76
- "@sanity/cli-core": "1.2.0"
76
+ "@sanity/cli-core": "1.3.0"
77
77
  },
78
78
  "engines": {
79
79
  "node": ">=20.19.1 <22 || >=22.12"