import upath from 'upath'; import type { DeepMockProxy } from 'vitest-mock-extended'; import type { RenovateConfig } from '../lib/config/types.ts'; import * as _logger from '../lib/logger/index.ts'; import type { Platform } from '../lib/modules/platform/index.ts'; import { platform as _platform } from '../lib/modules/platform/index.ts'; import { scm as _scm } from '../lib/modules/platform/scm.ts'; import * as _env from '../lib/util/exec/env.ts'; import * as _fs from '../lib/util/fs/index.ts'; import * as _git from '../lib/util/git/index.ts'; import { hash } from '../lib/util/hash.ts'; import * as _hostRules from '../lib/util/host-rules.ts'; import { type LongCommitSha, toLongCommitSha, } from '../lib/util/schema-utils/git.ts'; /** * Simple wrapper for getting mocked version of a module * @param module module which is mocked by `vitest-mock-extended.mockDeep` */ export function mockedExtended(module: T): DeepMockProxy { return module as DeepMockProxy; } /** * Simply wrapper to create partial mocks. * @param obj Object to cast to final type */ export function partial(): T; export function partial(obj: Partial): T; export function partial(obj: Partial[]): T[]; export function partial(obj: unknown = {}): unknown { return obj; } export const fs = vi.mocked(_fs); export const git = vi.mocked(_git); export const platform = vi.mocked(partial>(_platform)); export const scm = vi.mocked(_scm); export const env = vi.mocked(_env); export const hostRules = vi.mocked(_hostRules); export const logger = vi.mocked(_logger, true); export type { RenovateConfig }; function getCallerFileName(): string | null { let result: string | null = null; const prepareStackTrace = Error.prepareStackTrace; const stackTraceLimit = Error.stackTraceLimit; Error.prepareStackTrace = (_err, stack) => stack; Error.stackTraceLimit = 5; // max calls inside this file + 1 try { const err = new Error(); const stack = err.stack as unknown as NodeJS.CallSite[]; let currentFile: string | null = null; for (const frame of stack) { const fileName = frame.getFileName() ?? null; if (!currentFile) { currentFile = fileName; } else if (currentFile !== fileName) { result = fileName; break; } } } catch { // no-op } Error.prepareStackTrace = prepareStackTrace; Error.stackTraceLimit = stackTraceLimit; return result; } export function getFixturePath(fixtureFile: string, fixtureRoot = '.'): string { const callerDir = upath.dirname(getCallerFileName()!); return upath.join(callerDir, fixtureRoot, '__fixtures__', fixtureFile); } /** * Deterministically derive a valid {@link LongCommitSha} from a seed, for tests. * Same seed always yields the same SHA, keeping snapshots stable. * Defaults to a 40-char (sha1) hash; pass 'sha256' for a 64-char hash. */ export function fakeSha( seed: string, algorithm: 'sha1' | 'sha256' = 'sha1', ): LongCommitSha { return toLongCommitSha(hash(seed, algorithm)); } /** * Variables that `vi.stubEnv()` treats as booleans: it maps them onto '1' / '' * rather than deleting them, so they cannot be cleared through a stub. * Vitest sets them itself, and nothing under test reads them. */ const unstubbableEnvVars = new Set(['PROD', 'DEV', 'SSR']); /** * Clear every environment variable for the duration of the current test. * * Replacing `process.env` wholesale would break `vi.stubEnv()`, which captures * the original object when the worker starts and would keep deleting from it. * Stubbing each key instead keeps that intact, and `unstubEnvs` restores them * all before the next test. */ export function clearEnv(): void { for (const key of Object.keys(process.env)) { if (!unstubbableEnvVars.has(key)) { vi.stubEnv(key, undefined); } } }