Repository: okonet/lint-staged (js)

Issue:
jest can't find babel when i'm using gitDir
Hello okonet,
thank you for your great work.
I'm trying to use jest with lint staged, but when i'm using the "gitDir" option jest can't find babel-jest and so every test fails.

My config:
```
{
    "gitDir": "../",
    "linters": {
        "*.js": [
            "prettier --single-quote --trailing-comma all --write",
            "git add",
            "eslint --ignore-path ./gui/.gitignore",
            "jest --config ./gui/jest.json --bail --findRelatedTests"
        ],
        "*.css": [
            "stylelint"
        ]
    }
}
```

My folder structure:
gitFolder -> gui (frontend-app)

`^^^^^^ SyntaxError: Unexpected token import at transformAndBuildScript (gui/node_modules/jest-runtime/build/transform.js:320:12)`

I think the problem is that jest can't find babel-jest, because of the "gitDir"-option and so can't transform the import statement.

When i'm using jest without lint-staged it's working like a charm.

lint-staged: 3.4.0
jest: 19.0.2
babel-jest: 19.0.0
husky: 0.13.3

I hope you've got an idea where the problem comes from.
Thank you

Pull request description:
Fix gitDir Bug for git specific executables
### Changelog
+ changing `res.bin !== 'npm'` to `res.bin === 'git'`

### Why
It's not possible to get the getDir path for git specific executions, in underlying directory paths and doing a precommit for lint-staged. Using `'git'` options specifically declares to use options that include the getDir option for doing precommits.   

### TODO
- [x] use 'git' options only

### Notes
---

<details>
<summary>Error report</summary>
<pre><code>SyntaxError: Unexpected token import at transformAndBuildScript (gui/node_modules/jest-
    runtime/build/transform.js:320:12)
</code></pre>
</p></details>

Closes #158

Patch:
diff --git a/package.json b/package.json
index 5433dc2..5d9cbcb 100644
--- a/package.json
+++ b/package.json
@@ -64,7 +64,7 @@
     "eslint-config-okonet": "^1.1.1",
     "expect": "^1.20.2",
     "is-promise": "^2.1.0",
-    "jest": "^19.0.2",
+    "jest": "^20.0.1",
     "jsonlint": "^1.6.2",
     "jsonlint-cli": "^1.0.1",
     "npm-check": "^5.2.2",
diff --git a/src/runScript.js b/src/runScript.js
index d5af31b..970ef88 100644
--- a/src/runScript.js
+++ b/src/runScript.js
@@ -10,8 +10,10 @@ module.exports = function runScript(commands, pathsToLint, packageJson, options)
         task: () => {
             try {
                 const res = findBin(linter, pathsToLint, packageJson, options)
+                // Only use gitDir as CWD if we are using the git binary
+                // e.g `npm` should run tasks in the actual CWD
                 const execaOptions =
-                    res.bin !== 'npm' && options && options.gitDir ? { cwd: options.gitDir } : {}
+                    res.bin.endsWith('git') && options && options.gitDir ? { cwd: options.gitDir } : {}
                 return new Promise((resolve, reject) => {
                     execa(res.bin, res.args, execaOptions)
                         .then(() => {
@@ -29,4 +31,3 @@ ${ err.stdout }`))
         }
     }))
 }
-


Test patch:
diff --git a/test/__mocks__/execa.js b/test/__mocks__/execa.js
index 2321038..b4bbacb 100644
--- a/test/__mocks__/execa.js
+++ b/test/__mocks__/execa.js
@@ -1,3 +1,1 @@
-jest.genMockFromModule('execa')
-
 module.exports = jest.fn()
diff --git a/test/runScript-mock-findBin.spec.js b/test/runScript-mock-findBin.spec.js
new file mode 100644
index 0000000..139d691
--- /dev/null
+++ b/test/runScript-mock-findBin.spec.js
@@ -0,0 +1,65 @@
+// This is in a separate test file because I was unable to get `jest.mock` working in a test block
+// `jest.mock` gets hoisted, but even with `jest.doMock` it wasn't working
+/* eslint no-underscore-dangle: 0 */
+
+import expect from 'expect'
+import isPromise from 'is-promise'
+import mockFn from 'execa'
+import runScript from '../src/runScript'
+
+jest.mock('execa')
+
+// Mock findBin to return an absolute path
+jest.mock('../src/findBin', () => (commands, paths) => {
+    const [
+      bin,
+      ...otherArgs
+    ] = commands.split(' ')
+
+    return ({
+        bin: `/usr/local/bin/${ bin }`,
+        args: otherArgs.concat(['--']).concat(paths)
+    })
+}, { virtual: true })
+
+expect.extend({
+    toBeAPromise() {
+        expect.assert(
+            isPromise(this.actual),
+            'expected %s to be a Promise',
+            this.actual
+        )
+        return this
+    }
+})
+
+const packageJSON = {
+    scripts: {
+        test: 'noop',
+        test2: 'noop'
+    },
+    'lint-staged': {}
+}
+
+describe.only('runScript with absolute paths', () => {
+    beforeEach(() => {
+        mockFn.mockReset()
+        mockFn.mockImplementation(() => new Promise(() => {}))
+    })
+
+    it('can pass `gitDir` as `cwd` to `execa()` when git is called via absolute path', () => {
+        const res = runScript(
+          ['git add'],
+          'test.js',
+          packageJSON,
+          { gitDir: '../' }
+        )
+
+        expect(res[0].task()).toBeAPromise()
+        expect(mockFn.mock.calls.length).toEqual(1)
+        expect(mockFn.mock.calls[0][0]).toMatch('/usr/local/bin/git')
+        expect(mockFn.mock.calls[0][1]).toEqual(['add', '--', 'test.js'])
+        expect(mockFn.mock.calls[0][2]).toEqual({ cwd: '../' })
+    })
+})
+
diff --git a/test/runScript.spec.js b/test/runScript.spec.js
index 7ea93b0..a122515 100644
--- a/test/runScript.spec.js
+++ b/test/runScript.spec.js
@@ -30,6 +30,7 @@ describe('runScript', () => {
 
     beforeEach(() => {
         mockFn.mockReset()
+        mockFn.mockImplementation(() => new Promise(() => {}))
     })
 
     it('should return an array', () => {
@@ -105,6 +106,20 @@ describe('runScript', () => {
         expect(mockFn.mock.calls[1][2]).toEqual({ cwd: '../' })
     })
 
+    it('should not pass `gitDir` as `cwd` to `execa()` if a non-git binary is called', () => {
+        const res = runScript(
+          ['jest'],
+          'test.js',
+          packageJSON,
+          { gitDir: '../' }
+        )
+        expect(res[0].task()).toBeAPromise()
+        expect(mockFn.mock.calls.length).toEqual(1)
+        expect(mockFn.mock.calls[0]).toEqual(
+          ['jest', ['--', 'test.js'], {}]
+        )
+    })
+
     it('should use --silent in non-verbose mode', () => {
         const res = runScript(
             'test',
@@ -133,4 +148,3 @@ describe('runScript', () => {
         )
     })
 })
-