Skip to content

Commit

Permalink
test: add git tests
Browse files Browse the repository at this point in the history
  • Loading branch information
azz committed Jan 8, 2018
1 parent eaba978 commit 449a863
Show file tree
Hide file tree
Showing 8 changed files with 234 additions and 11 deletions.
21 changes: 21 additions & 0 deletions __mocks__/execa.js
@@ -0,0 +1,21 @@
const mockStream = () => ({
once: jest.fn(),
on: jest.fn(),
removeListener: jest.fn(),
pipe: jest.fn(),
});

const mockExeca = jest.fn().mockReturnValue({
stdout: mockStream(),
stderr: mockStream(),
kill: () => {},
});

const mockExecaSync = jest.fn().mockReturnValue({
stdout: '',
stderr: '',
kill: () => {},
});

module.exports = mockExeca;
module.exports.sync = mockExecaSync;
20 changes: 20 additions & 0 deletions __mocks__/prettier.js
@@ -0,0 +1,20 @@
const prettierMock = {
format: jest.fn().mockImplementation(input => 'formatted:' + input),
resolveConfig: {
sync: jest.fn().mockImplementation(file => ({ file })),
},
getSupportInfo: jest.fn().mockReturnValue({
languages: [
{
name: 'JavaScript',
extensions: ['.js'],
},
{
name: 'Markdown',
extensions: ['.md'],
},
],
}),
};

module.exports = prettierMock;
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -40,6 +40,7 @@
"eslint-plugin-prettier": "^2.4.0",
"husky": "^0.14.3",
"jest": "^22.0.4",
"mock-fs": "^4.4.2",
"prettier": "1.9.2",
"semantic-release": "^11.0.2"
}
Expand Down
18 changes: 16 additions & 2 deletions src/__tests__/pretty-quick.test.js
@@ -1,3 +1,17 @@
it('has not tests', () => {
// yet...
import mock from 'mock-fs';

import prettyQuick from '..';

jest.mock('execa');

afterEach(() => mock.restore());

test('throws an error when no vcs is found', () => {
mock({
'root/README.md': '',
});

expect(() => prettyQuick('root')).toThrowError(
'Unable to detect a source control manager.'
);
});
162 changes: 162 additions & 0 deletions src/__tests__/scm-git.test.js
@@ -0,0 +1,162 @@
import mock from 'mock-fs';
import execa from 'execa';
import fs from 'fs';

import prettyQuick from '..';

jest.mock('execa');

afterEach(() => {
mock.restore();
jest.clearAllMocks();
});

const mockGitFs = () => {
mock({
'root/.git': {},
'root/foo.js': 'foo()',
'root/bar.md': '# foo',
});
execa.sync.mockImplementation((command, args) => {
if (command !== 'git') {
throw new Error(`unexpected command: ${command}`);
}
switch (args[0]) {
case 'ls-files':
return { stdout: '' };
case 'diff':
return { stdout: './foo.js\n' + './bar.md\n' };
case 'add':
return { stdout: '' };
default:
throw new Error(`unexpected arg0: ${args[0]}`);
}
});
};

describe('with git', () => {
test('calls `git merge-base`', () => {
mock({
'root/.git': {},
});

prettyQuick('root');

expect(execa.sync).toHaveBeenCalledWith(
'git',
['merge-base', 'HEAD', 'master'],
{ cwd: 'root' }
);
});

test('with --staged does NOT call `git merge-base`', () => {
mock({
'root/.git': {},
});

prettyQuick('root');

expect(execa.sync).not.toHaveBeenCalledWith('git', [
'merge-base',
'HEAD',
'master',
]);
});

test('calls `git diff --name-only` with revision', () => {
mock({
'root/.git': {},
});

prettyQuick('root', { since: 'banana' });

expect(execa.sync).toHaveBeenCalledWith(
'git',
['diff', '--name-only', '--diff-filter=ACMRTUB', 'banana'],
{ cwd: 'root' }
);
});

test('calls `git ls-files`', () => {
mock({
'root/.git': {},
});

prettyQuick('root', { since: 'banana' });

expect(execa.sync).toHaveBeenCalledWith(
'git',
['ls-files', '--others', '--exclude-standard'],
{ cwd: 'root' }
);
});

test('calls onFoundSinceRevision with return value from `git merge-base`', () => {
const onFoundSinceRevision = jest.fn();

mock({
'root/.git': {},
});
execa.sync.mockReturnValue({ stdout: 'banana' });

prettyQuick('root', { onFoundSinceRevision });

expect(onFoundSinceRevision).toHaveBeenCalledWith('git', 'banana');
});

test('calls onFoundChangedFiles with changed files', () => {
const onFoundChangedFiles = jest.fn();
mockGitFs();

prettyQuick('root', { since: 'banana', onFoundChangedFiles });

expect(onFoundChangedFiles).toHaveBeenCalledWith(['./foo.js', './bar.md']);
});

test('calls onWriteFile with changed files', () => {
const onWriteFile = jest.fn();
mockGitFs();

prettyQuick('root', { since: 'banana', onWriteFile });

expect(onWriteFile).toHaveBeenCalledWith('./foo.js');
expect(onWriteFile).toHaveBeenCalledWith('./bar.md');
});

test('writes formatted files to disk', () => {
const onWriteFile = jest.fn();

mockGitFs();

prettyQuick('root', { since: 'banana', onWriteFile });

expect(fs.readFileSync('root/foo.js', 'utf8')).toEqual('formatted:foo()');
expect(fs.readFileSync('root/bar.md', 'utf8')).toEqual('formatted:# foo');
});

test('with --staged stages changed files', () => {
mockGitFs();

prettyQuick('root', { since: 'banana', staged: true });

expect(execa.sync).toHaveBeenCalledWith('git', ['add', './foo.js'], {
cwd: 'root',
});
expect(execa.sync).toHaveBeenCalledWith('git', ['add', './bar.md'], {
cwd: 'root',
});
});

test('without --staged does NOT stage changed files', () => {
mockGitFs();

prettyQuick('root', { since: 'banana' });

expect(execa.sync).not.toHaveBeenCalledWith('git', ['add', './foo.js'], {
cwd: 'root',
});
expect(execa.sync).not.toHaveBeenCalledWith('git', ['add', './bar.md'], {
cwd: 'root',
});
});
});
10 changes: 6 additions & 4 deletions src/formatFiles.js
@@ -1,20 +1,22 @@
import { readFileSync, writeFileSync } from 'fs';
import { resolveConfig, format } from 'prettier';
import { join } from 'path';

export default (files, { config, onWriteFile }) => {
for (const file of files) {
export default (directory, files, { config, onWriteFile } = {}) => {
for (const relative of files) {
const file = join(directory, relative);
const options = resolveConfig.sync(file, { config });
const input = readFileSync(file, 'utf8');
const output = format(
input,
Object.assign(options, {
Object.assign({}, options, {
filepath: file,
})
);

if (output !== input) {
writeFileSync(file, output);
onWriteFile && onWriteFile(file);
onWriteFile && onWriteFile(relative);
}
}
};
9 changes: 4 additions & 5 deletions src/index.js
Expand Up @@ -14,7 +14,7 @@ export default (
onFoundSinceRevision,
onFoundChangedFiles,
onWriteFile,
}
} = {}
) => {
const scm = scms(directory);
if (!scm) {
Expand All @@ -27,17 +27,16 @@ export default (

const changedFiles = scm
.getChangedFiles(directory, revision)
.map(file => relative(directory, file))
.filter(isSupportedExtension)
.filter(createIgnorer(directory));

onFoundChangedFiles && onFoundChangedFiles(changedFiles);

formatFiles(changedFiles, {
formatFiles(directory, changedFiles, {
config,
onWriteFile: file => {
onWriteFile(file);
scm.stageFile(directory, file);
onWriteFile && onWriteFile(file);
staged && scm.stageFile(directory, file);
},
});
};
4 changes: 4 additions & 0 deletions yarn.lock
Expand Up @@ -3114,6 +3114,10 @@ minimist@~0.0.1:
dependencies:
minimist "0.0.8"

mock-fs@^4.4.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.4.2.tgz#09dec5313f97095a450be6aa2ad8ab6738d63d6b"

modify-values@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.0.tgz#e2b6cdeb9ce19f99317a53722f3dbf5df5eaaab2"
Expand Down

0 comments on commit 449a863

Please sign in to comment.