UNPKG

@interaktiv/dia-scripts

Version:

CLI toolbox with common scripts for most sort of projects at DIA

548 lines (528 loc) 15.8 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); jest.mock('read-pkg-up', () => ({ sync: jest.fn(() => ({ package: {}, path: '/blah/package.json' })) })); jest.mock('which', () => ({ sync: jest.fn(() => {}) })); jest.mock('rimraf', () => ({ sync: jest.fn() })); jest.mock('hosted-git-info', () => ({ fromUrl: jest.fn(() => ({ type: 'bitbucket' })) })); // eslint-disable-next-line max-lines-per-function describe('utils', () => { let whichSyncMock, readPkgUpSyncMock, rimrafSyncMock, hostedGitInfoFromUrlMock; beforeEach(() => { jest.resetModules(); whichSyncMock = require('which').sync; readPkgUpSyncMock = require('read-pkg-up').sync; rimrafSyncMock = require('rimraf').sync; hostedGitInfoFromUrlMock = require('hosted-git-info').fromUrl; }); function mockPkg({ pkg = {}, path = '/blah/package.json' }) { readPkgUpSyncMock.mockImplementationOnce(() => ({ package: pkg, path })); } test('pkg is the package.json', () => { const myPkg = { name: 'blah' }; mockPkg({ pkg: myPkg }); expect(require('./utils').pkg).toBe(myPkg); }); test('appDirectory is the dirname to the package.json', () => { const pkgPath = '/some/path/to'; mockPkg({ path: `${pkgPath}/package.json` }); expect(require('./utils').appDirectory).toBe(pkgPath); }); test('resolveSelf resolves to src/index.js when in the dia-scripts package', () => { mockPkg({ pkg: { name: '@interaktiv/dia-scripts' } }); expect(require('./utils').resolveSelf()).toBe(require.resolve('.').replace(process.cwd(), '.')); }); test('resolveSelf resolves to dia-scripts if not in the dia-scripts package', () => { mockPkg({ pkg: { name: 'not-dia-scripts' } }); whichSyncMock.mockImplementationOnce(() => require.resolve('.')); expect(require('./utils').resolveSelf()).toBe('dia-scripts'); }); test(`resolveBin resolves to the full path when it's not in $PATH`, () => { expect(require('./utils').resolveBin('cross-env')).toBe(require.resolve('cross-env/src/bin/cross-env').replace(process.cwd(), '.')); }); test(`resolveBin resolves to the binary if it's in $PATH`, () => { whichSyncMock.mockImplementationOnce(() => require.resolve('cross-env/src/bin/cross-env').replace(process.cwd(), '.')); expect(require('./utils').resolveBin('cross-env')).toBe('cross-env'); expect(whichSyncMock).toHaveBeenCalledTimes(1); expect(whichSyncMock).toHaveBeenCalledWith('cross-env'); }); describe('for windows', () => { let realpathSync; beforeEach(() => { jest.doMock('fs-extra', () => ({ realpathSync: jest.fn() })); ({ realpathSync } = require('fs-extra')); }); afterEach(() => { jest.unmock('fs-extra'); }); test('resolveBin resolves to .bin path when which returns a windows-style cmd', () => { const fullBinPath = '\\project\\node_modules\\.bin\\concurrently.CMD'; realpathSync.mockImplementation(() => fullBinPath); expect(require('./utils').resolveBin('concurrently')).toBe(fullBinPath); expect(realpathSync).toHaveBeenCalledTimes(2); }); }); // TODO: What the heck is going on here? test('getConcurrentlyArgs gives good args to pass to concurrently', () => { expect(require('./utils').getConcurrentlyArgs({ build: 'echo build', lint: 'echo lint', test: 'echo test', validate: 'echo validate', a: 'echo a', b: 'echo b', c: 'echo c', d: 'echo d', e: 'echo e', f: 'echo f', g: 'echo g', h: 'echo h', i: 'echo i', j: 'echo j' })).toMatchSnapshot(); }); test('parseEnv parses the existing environment variable', () => { const globals = { react: 'React', 'prop-types': 'PropTypes' }; process.env.BUILD_GLOBALS = JSON.stringify(globals); expect(require('./utils').parseEnv('BUILD_GLOBALS')).toEqual(globals); delete process.env.BUILD_GLOBALS; }); test(`parseEnv returns the default if the environment variable doesn't exist`, () => { const defaultVal = { hello: 'world' }; expect(require('./utils').parseEnv('DOES_NOT_EXIST', defaultVal)).toBe(defaultVal); }); test('ifAnyDep returns the true argument if true and false argument if false', () => { mockPkg({ pkg: { peerDependencies: { react: '*' } } }); const t = { a: 'b' }; const f = { c: 'd' }; expect(require('./utils').ifAnyDep('react', t, f)).toBe(t); expect(require('./utils').ifAnyDep('preact', t, f)).toBe(f); }); test('ifAnyDep works with arrays of dependencies', () => { mockPkg({ pkg: { peerDependencies: { react: '*' } } }); const t = { a: 'b' }; const f = { c: 'd' }; expect(require('./utils').ifAnyDep(['preact', 'react'], t, f)).toBe(t); expect(require('./utils').ifAnyDep(['preact', 'webpack'], t, f)).toBe(f); }); test('ifScript returns the true argument if true and the false argument if false', () => { mockPkg({ pkg: { scripts: { build: 'echo build' } } }); const t = { e: 'f' }; const f = { g: 'h' }; expect(require('./utils').ifScript('build', t, f)).toBe(t); expect(require('./utils').ifScript('lint', t, f)).toBe(f); }); test('ifFile returns the true argument if true and the false argument if false', () => { mockPkg({ path: require.resolve('../package.json') }); const t = { e: 'f' }; const f = { g: 'h' }; expect(require('./utils').ifFile('package.json', t, f)).toBe(t); expect(require('./utils').ifFile('does-not-exist.blah', t, f)).toBe(f); }); test('isWindows returns true if on windows otherwise false', () => { const { platform: originalPlatform } = process; Object.defineProperty(process, 'platform', { value: 'win32' }); expect(require('./utils').isWindows()).toBe(true); Object.defineProperty(process, 'platform', { value: 'MockOS' }); expect(require('./utils').isWindows()).toBe(false); Object.defineProperty(process, 'platform', { value: originalPlatform }); }); test('getSupportedNodeVersion returns 8.0.0 for a range of >=8', () => { mockPkg({ pkg: { engines: { node: '>=8' } } }); expect(require('./utils').getSupportedNodeVersion(require('./utils').pkg)).toBe('8.0.0'); }); describe('ifSfdxProject', () => { const mock = require('mock-fs'); beforeEach(() => { mockPkg({ path: `${'/some/path/to'}/package.json` }); }); afterEach(() => { mock.restore(); }); test('ifSfdxProject returns true argument', () => { mock({ [require('./utils').fromRoot('sfdx-project.json')]: '{}' }); const t = { i: 'j' }; expect(require('./utils').ifSfdxProject(t, { k: 'l' })).toBe(t); }); test('ifSfdxProject returns false argument', () => { const f = { k: 'l' }; expect(require('./utils').ifSfdxProject({ i: 'j' }, f)).toBe(f); }); }); describe('ifTitaniumProject', () => { const mock = require('mock-fs'); beforeEach(() => { mockPkg({ pkg: { name: 'my-fancy-titanium-project' }, path: `${'/some/path/to'}/package.json` }); }); afterEach(() => { mock.restore(); }); it('should return true argument for existent tiapp.xml', () => { mock({ [require('./utils').fromRoot('tiapp.xml')]: '' }); const t = { i: 'j' }; expect(require('./utils').ifTitaniumProject(t, { k: 'l' })).toBe(t); }); it('should return true argument for existent tiapp.tpl', () => { mock({ [require('./utils').fromRoot('tiapp.tpl')]: '{}' }); const t = { i: 'j' }; expect(require('./utils').ifTitaniumProject(t, { k: 'l' })).toBe(t); }); it('should return true argument for existent tiapp-cfg.json', () => { mock({ [require('./utils').fromRoot('tiapp-cfg.json')]: '{}' }); const t = { i: 'j' }; expect(require('./utils').ifTitaniumProject(t, { k: 'l' })).toBe(t); }); it('should return false argument if false', () => { const f = { k: 'l' }; expect(require('./utils').ifTitaniumProject({ i: 'j' }, f)).toBe(f); }); }); test('ifCommerceProject returns true argument if true and false argument if false', () => { const mock = require('mock-fs'); mock({ [require('./utils').fromRoot('shopware.php')]: '{}' }); const t = { i: 'j' }; const f = { k: 'l' }; expect(require('./utils').ifCommerceProject(t, f)).toBe(t); mock.restore(); expect(require('./utils').ifCommerceProject(t, f)).toBe(f); }); test('ifCI returns true argument if true and false argument if false', () => { const t = { m: 'n' }; const f = { o: 'p' }; const utils = require('./utils'); utils.ifCI = jest.fn(); utils.ifCI // Default .mockImplementation(_t => _t) // First call .mockImplementationOnce(_t => _t) // Second call .mockImplementationOnce((_t, _f) => _f); expect(require('./utils').ifCI(t, f)).toBe(t); expect(require('./utils').ifCI(t, f)).toBe(f); }); describe('runAll', () => { let originalConsoleLog, originalExit, crossSpawnSyncMock; beforeEach(() => { ({ sync: crossSpawnSyncMock } = require('cross-spawn')); originalConsoleLog = console.log; console.log = jest.fn(); originalExit = process.exit; process.exit = jest.fn(); }); afterEach(() => { console.log = originalConsoleLog; process.exit = originalExit; jest.resetModules(); }); it('should throw if any script fails', () => { crossSpawnSyncMock.mockImplementationOnce(() => ({ status: 500 })); expect(() => { require('./utils').runAll([{ name: 'unit-test', task: 'my-fancy-command', args: ['firstArg secondArg --niceFlag'] }]); }).toThrow(/exited with code/); }); }); describe('isGithubRepo', () => { it('should return true if github is stored in package.json repo url prop', () => { hostedGitInfoFromUrlMock.mockImplementationOnce(() => ({ type: 'github' })); expect(require('./utils').isGithubRepo()).toBe(true); }); it('should return false if any other url in package.json repo url prop', () => { hostedGitInfoFromUrlMock.mockImplementationOnce(() => ({ type: 'bitbucket' })); expect(require('./utils').isGithubRepo()).toBe(false); }); it('should return false if could not get git info', () => { hostedGitInfoFromUrlMock.mockImplementationOnce(() => null); expect(require('./utils').isGithubRepo()).toBe(false); }); }); describe('ifGithubRepo', () => { afterEach(() => { jest.resetModules(); }); it('should return true argument if true', () => { hostedGitInfoFromUrlMock.mockImplementationOnce(() => ({ type: 'github' })); const t = { q: 'r' }; expect(require('./utils').ifGithubRepo(t, { s: 't' })).toBe(t); }); it('should return false argument if false', () => { hostedGitInfoFromUrlMock.mockImplementationOnce(() => ({ type: 'bitbucket' })); const f = { s: 't' }; expect(require('./utils').ifGithubRepo({ q: 'r' }, f)).toBe(f); }); }); describe('isBitbucketRepo', () => { afterEach(() => { jest.resetModules(); }); it('should return false if any other url in package.json repo url prop', () => { hostedGitInfoFromUrlMock.mockImplementationOnce(() => ({ type: 'github' })); expect(require('./utils').isBitbucketRepo()).toBe(false); }); it('should return false if could not get git info', () => { hostedGitInfoFromUrlMock.mockImplementationOnce(() => null); expect(require('./utils').isBitbucketRepo()).toBe(false); }); }); describe('cleanDir', () => { beforeEach(() => { ({ sync: rimrafSyncMock } = require('rimraf')); }); afterEach(() => { jest.resetModules(); }); it('should do nothing if path is invalid', () => { require('./utils').cleanDir(null); require('./utils').cleanDir(undefined); require('./utils').cleanDir(false); expect(rimrafSyncMock).toBeCalledTimes(0); }); it('should run if path is given (existent or not)', () => { const dir = '/path/to/dir'; require('./utils').cleanDir(dir); expect(rimrafSyncMock).toBeCalledWith(dir); }); }); describe('createPmdMetaDataBundle', () => { let crossSpawnSyncMock, originalExit; beforeEach(() => { whichSyncMock.mockImplementationOnce(() => 'sfdx'); jest.mock('fs', () => (0, _extends2.default)({}, jest.requireActual('fs'), { realpathSync: jest.fn(path => path) })); ({ sync: crossSpawnSyncMock } = require('cross-spawn')); ({ sync: rimrafSyncMock } = require('rimraf')); originalExit = process.exit; process.exit = jest.fn(); }); afterEach(() => { process.exit = originalExit; jest.resetModules(); }); it.each` title | args ${'call sfdx cli with default source and cleans destination priorly'} | ${{}} ${'call sfdx cli with default source but does not clean destination priorly'} | ${{ clean: false }} ${'call sfdx cli with given source dir'} | ${{ sourceDir: '/custom/force-app' }} `('$title', ({ args }) => { const { createPmdMetaDataBundle, fromRoot } = require('./utils'); const { sourceDir = fromRoot('force-app'), clean = true } = args; createPmdMetaDataBundle(sourceDir, clean, !!sourceDir); expect(rimrafSyncMock).toBeCalledTimes(clean === true ? 1 : 0); expect(crossSpawnSyncMock).toHaveBeenCalledTimes(1); const [firstCall] = crossSpawnSyncMock.mock.calls; const [script, calledArgs] = firstCall; expect([script, ...calledArgs].join(' ')).toMatchSnapshot(); }); }); test('isOptedOut should return true', () => { const mock = require('mock-fs'); mock({ [require('./utils').fromRoot('.opt-out')]: 'autoformat' }); const t = { u: 'v' }; expect(require('./utils').isOptedOut('autoformat', t, { w: 'x' })).toBe(t); mock.restore(); }); describe('isOptedIn', () => { const mock = require('mock-fs'); it('should return true argument if true and false argument if false', () => { mock({ [require('./utils').fromRoot('.opt-in')]: 'reportcoverage' }); const t = { y: 'z' }; const f = { 1: '2' }; expect(require('./utils').isOptedIn('reportcoverage', t, f)).toBe(t); mock.restore(); expect(require('./utils').isOptedIn('reportcoverage', t, f)).toBe(f); }); }); });