@interaktiv/dia-scripts
Version:
CLI toolbox with common scripts for most sort of projects at DIA
548 lines (528 loc) • 15.8 kB
JavaScript
;
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);
});
});
});