jest.mock('child_process', () => ({ execFileSync: jest.fn(), })); jest.mock('fs', () => ({ readFileSync: jest.fn(), mkdtempSync: jest.fn(), readdirSync: jest.fn(), rmSync: jest.fn(), renameSync: jest.fn(), })); jest.mock('os', () => ({ tmpdir: () => '/tmp', })); jest.mock('path', () => ({ join: (...parts: string[]) => parts.join('/'), })); import { execFileSync } from 'child_process'; import fs from 'fs'; import { createLocalPackageTarball } from '../../src/scripts/local-pack'; describe('createLocalPackageTarball', () => { it('creates tarball and renames it', async () => { const readFileSync = fs.readFileSync as jest.Mock; readFileSync.mockReturnValueOnce(JSON.stringify({ version: '1.0.0' })); (fs.mkdtempSync as jest.Mock).mockReturnValueOnce('/tmp/pack'); (fs.readdirSync as jest.Mock).mockReturnValueOnce(['pkg.tgz']); const result = await createLocalPackageTarball({ projectRoot: '/repo', outputDir: '/out', packageName: 'test-package', }); expect(execFileSync).toHaveBeenCalledWith( 'npm', ['pack', '--silent', '--pack-destination', '/tmp/pack'], expect.objectContaining({ cwd: '/repo', stdio: 'pipe' }), ); expect(fs.renameSync).toHaveBeenCalledWith( '/tmp/pack/pkg.tgz', '/out/test-package-v1.0.0.tgz', ); expect(fs.rmSync).toHaveBeenCalledWith('/tmp/pack', { recursive: true, force: true, }); expect(result).toBe('/out/test-package-v1.0.0.tgz'); }); it('throws when version missing', async () => { const readFileSync = fs.readFileSync as jest.Mock; readFileSync.mockReturnValueOnce(JSON.stringify({})); await expect( createLocalPackageTarball({ projectRoot: '/repo' }), ).rejects.toThrow('Unable to determine package version from package.json.'); }); it('throws when pack outputs multiple files', async () => { const readFileSync = fs.readFileSync as jest.Mock; readFileSync.mockReturnValueOnce(JSON.stringify({ version: '1.0.0' })); (fs.mkdtempSync as jest.Mock).mockReturnValueOnce('/tmp/pack'); (fs.readdirSync as jest.Mock).mockReturnValueOnce(['a.tgz', 'b.tgz']); await expect( createLocalPackageTarball({ projectRoot: '/repo' }), ).rejects.toThrow( 'Unexpected npm pack output. Expected a single .tgz file.', ); expect(fs.rmSync).toHaveBeenCalledWith('/tmp/pack', { recursive: true, force: true, }); }); });