import { describe, beforeEach, test, jest, expect } from '@jest/globals'; import { Knifecycle, constant } from 'knifecycle'; import initBuildPackageGitHooks from './gitHooks.js'; import { type GitHooksTransformer, type BuildPackageGitHooksService, } from './gitHooks.js'; import { type ImporterService, LogService } from 'common-services'; import { type FSService } from './fs.js'; describe('buildPackageGitHooks', () => { const writeFileAsync = jest.fn(); const readFileAsync = jest.fn(); const log = jest.fn(); const importer = jest.fn< ImporterService<{ default: GitHooksTransformer }> >(); let $: Knifecycle; beforeEach(() => { writeFileAsync.mockReset(); readFileAsync.mockReset(); log.mockReset(); importer.mockReset(); $ = new Knifecycle(); $.register(constant('log', log)); $.register(constant('PROJECT_DIR', '/home/whoiam/project/dir')); $.register(constant('EOL', '\n')); $.register( constant('fs', { readFileAsync: readFileAsync, writeFileAsync: writeFileAsync, }), ); $.register(constant('importer', importer)); $.register(initBuildPackageGitHooks); }); test('should work with one module and one config', async () => { $.register(constant('ENV', {})); $.register( constant('GIT_HOOKS_DIR', '/home/whoiam/project/dir/.git/hooks'), ); importer.mockResolvedValueOnce({ default: (hooks) => { hooks['pre-commit'] = hooks['pre-commit'] || []; hooks['pre-commit'].push('npm run test && npm run lint || exit 1'); return hooks; }, }); importer.mockRejectedValueOnce(new Error('E_ERROR_1')); importer.mockResolvedValueOnce({ default: (hooks) => { hooks['pre-commit'] = hooks['pre-commit'] || []; hooks['pre-commit'].push('npm run coveralls'); return hooks; }, }); importer.mockRejectedValueOnce(new Error('E_ERROR_2')); readFileAsync.mockResolvedValueOnce(Buffer.from('')); writeFileAsync.mockResolvedValueOnce(); const { buildPackageGitHooks } = await $.run<{ buildPackageGitHooks: BuildPackageGitHooksService; }>(['buildPackageGitHooks']); await buildPackageGitHooks( { metapak: { configs: ['_common'], data: {}, }, }, { configsSequence: ['_common'], modulesSequence: ['metapak-nfroidure', 'metapak-fantasia'], modulesConfigs: { 'metapak-nfroidure': { base: '/home/whoiam/project/dir/node_modules/metapak-nfroidure', srcDir: 'src', assetsDir: 'src', configs: ['_common', 'lol'], }, 'metapak-fantasia': { base: '/home/whoiam/project/dir/node_modules/metapak-fantasia', srcDir: 'src', assetsDir: 'src', configs: ['_common', 'test'], }, }, }, ); expect(importer.mock.calls).toEqual([ [ '/home/whoiam/project/dir/node_modules/metapak-nfroidure/src/_common/hooks.js', ], [ '/home/whoiam/project/dir/node_modules/metapak-fantasia/src/_common/hooks.js', ], ]); expect(writeFileAsync.mock.calls.map(bufferToText)).toEqual([ [ '/home/whoiam/project/dir/.git/hooks/pre-commit', '#!/bin/sh\n' + '# Automagically generated by metapak, do not change in place.\n' + '# Your changes would be loose on the next npm install run.\n' + 'npm run test && npm run lint || exit 1', { mode: 511 }, ], ]); expect(log.mock.calls.filter(filterLogs)).toEqual([ [ 'debug', '🤷 - No hooks found at:', '/home/whoiam/project/dir/node_modules/metapak-fantasia/src/_common/hooks.js', ], ]); }); test('should not run on CI', async () => { $.register( constant('ENV', { CI: 1, }), ); $.register( constant('GIT_HOOKS_DIR', '/home/whoiam/project/dir/.git/hooks'), ); importer.mockResolvedValueOnce({ default: (hooks) => { hooks['pre-commit'] = hooks['pre-commit'] || []; hooks['pre-commit'].push('npm run test && npm run lint || exit 1'); return hooks; }, }); importer.mockRejectedValueOnce(new Error('E_ERROR_1')); importer.mockResolvedValueOnce({ default: (hooks) => { hooks['pre-commit'] = hooks['pre-commit'] || []; hooks['pre-commit'].push('npm run coveralls'); return hooks; }, }); importer.mockRejectedValueOnce(new Error('E_ERROR_2')); readFileAsync.mockResolvedValueOnce(Buffer.from('')); writeFileAsync.mockResolvedValueOnce(); const { buildPackageGitHooks } = await $.run<{ buildPackageGitHooks: BuildPackageGitHooksService; }>(['buildPackageGitHooks']); await buildPackageGitHooks( { metapak: { configs: ['_common'], data: {}, }, }, { configsSequence: ['_common'], modulesSequence: ['metapak-nfroidure', 'metapak-fantasia'], modulesConfigs: { 'metapak-nfroidure': { base: '/home/whoiam/project/dir/node_modules/metapak-nfroidure', srcDir: 'src', assetsDir: 'src', configs: ['_common', 'lol'], }, 'metapak-fantasia': { base: '/home/whoiam/project/dir/node_modules/metapak-fantasia', srcDir: 'src', assetsDir: 'src', configs: ['_common', 'test'], }, }, }, ); expect(importer.mock.calls).toEqual([]); expect(writeFileAsync.mock.calls).toEqual([]); expect(log.mock.calls.filter(filterLogs)).toEqual([]); }); test('should not run on parent git repository', async () => { $.register(constant('ENV', {})); $.register(constant('GIT_HOOKS_DIR', '/home/whoiam/project/.git/hooks')); importer.mockResolvedValueOnce({ default: (hooks) => { hooks['pre-commit'] = hooks['pre-commit'] || []; hooks['pre-commit'].push('npm run test && npm run lint || exit 1'); return hooks; }, }); importer.mockRejectedValueOnce(new Error('E_ERROR_1')); importer.mockResolvedValueOnce({ default: (hooks) => { hooks['pre-commit'] = hooks['pre-commit'] || []; hooks['pre-commit'].push('npm run coveralls'); return hooks; }, }); importer.mockRejectedValueOnce(new Error('E_ERROR_2')); readFileAsync.mockResolvedValueOnce(Buffer.from('')); writeFileAsync.mockResolvedValueOnce(); const { buildPackageGitHooks } = await $.run<{ buildPackageGitHooks: BuildPackageGitHooksService; }>(['buildPackageGitHooks']); await buildPackageGitHooks( { metapak: { configs: ['_common'], data: {}, }, }, { configsSequence: ['_common'], modulesSequence: ['metapak-nfroidure', 'metapak-fantasia'], modulesConfigs: { 'metapak-nfroidure': { base: '/home/whoiam/project/dir/node_modules/metapak-nfroidure', srcDir: 'src', assetsDir: 'src', configs: ['_common', 'lol'], }, 'metapak-fantasia': { base: '/home/whoiam/project/dir/node_modules/metapak-fantasia', srcDir: 'src', assetsDir: 'src', configs: ['_common', 'test'], }, }, }, ); expect(importer.mock.calls).toEqual([]); expect(writeFileAsync.mock.calls).toEqual([]); expect(log.mock.calls.filter(filterLogs)).toEqual([]); }); }); function bufferToText( call: Parameters, ): [string, string, Parameters[2]] { return [call[0], call[1].toString(), call[2]]; } function filterLogs(e: Parameters) { return !e[0].endsWith('-stack'); }