diff --git a/test/manager/bundler/artifacts.spec.ts b/test/manager/bundler/artifacts.spec.ts
index dfc2f61f19b480d4a20acba788ef00e91555b674..c5df594893e364605e3f3df91735dbcd3c6f174a 100644
--- a/test/manager/bundler/artifacts.spec.ts
+++ b/test/manager/bundler/artifacts.spec.ts
@@ -1,18 +1,18 @@
 import _fs from 'fs-extra';
+import { exec as _exec } from 'child_process';
 import Git from 'simple-git/promise';
 import { updateArtifacts } from '../../../lib/manager/bundler';
-import * as _exec from '../../../lib/util/exec';
 import { platform as _platform } from '../../../lib/platform';
 import * as _datasource from '../../../lib/datasource/docker';
 import { mocked } from '../../util';
 
 const fs: jest.Mocked<typeof _fs> = _fs as any;
-const exec = mocked(_exec).exec;
+const exec: jest.Mock<typeof _exec> = _exec as any;
 const platform = mocked(_platform);
 const datasource = mocked(_datasource);
 
 jest.mock('fs-extra');
-jest.mock('../../../lib/util/exec');
+jest.mock('child_process');
 jest.mock('../../../lib/platform');
 jest.mock('../../../lib/datasource/docker');
 
@@ -31,9 +31,9 @@ describe('bundler.updateArtifacts()', () => {
   it('returns null if Gemfile.lock was not changed', async () => {
     platform.getFile.mockResolvedValueOnce('Current Gemfile.lock');
     fs.outputFile.mockResolvedValueOnce(null as never);
-    exec.mockResolvedValueOnce({
-      stdout: '',
-      stderr: '',
+    exec.mockImplementationOnce((cmd, _options, callback) => {
+      callback(null, '', '');
+      return undefined;
     });
     platform.getRepoStatus.mockResolvedValueOnce({
       modified: [],
@@ -46,9 +46,9 @@ describe('bundler.updateArtifacts()', () => {
   it('works for default binarySource', async () => {
     platform.getFile.mockResolvedValueOnce('Current Gemfile.lock');
     fs.outputFile.mockResolvedValueOnce(null as never);
-    exec.mockResolvedValueOnce({
-      stdout: '',
-      stderr: '',
+    exec.mockImplementationOnce((cmd, _options, callback) => {
+      callback(null, '', '');
+      return undefined;
     });
     platform.getRepoStatus.mockResolvedValueOnce({
       modified: ['Gemfile.lock'],
@@ -61,9 +61,9 @@ describe('bundler.updateArtifacts()', () => {
   it('works explicit global binarySource', async () => {
     platform.getFile.mockResolvedValueOnce('Current Gemfile.lock');
     fs.outputFile.mockResolvedValueOnce(null as never);
-    exec.mockResolvedValueOnce({
-      stdout: '',
-      stderr: '',
+    exec.mockImplementationOnce((cmd, _options, callback) => {
+      callback(null, '', '');
+      return undefined;
     });
     platform.getRepoStatus.mockResolvedValueOnce({
       modified: ['Gemfile.lock'],
@@ -89,12 +89,10 @@ describe('bundler.updateArtifacts()', () => {
           { version: '1.3.0' },
         ],
       });
-      exec.mockImplementationOnce(cmd => {
+      exec.mockImplementationOnce((cmd, _options, callback) => {
         dockerCommand = cmd;
-        return Promise.resolve({
-          stdout: '',
-          stderr: '',
-        });
+        callback(null, '', '');
+        return undefined;
       });
       platform.getRepoStatus.mockResolvedValueOnce({
         modified: ['Gemfile.lock'],
@@ -119,12 +117,10 @@ describe('bundler.updateArtifacts()', () => {
           { version: '1.3.0' },
         ],
       });
-      exec.mockImplementationOnce(cmd => {
+      exec.mockImplementationOnce((cmd, _options, callback) => {
         dockerCommand = cmd;
-        return Promise.resolve({
-          stdout: '',
-          stderr: '',
-        });
+        callback(null, '', '');
+        return undefined;
       });
       platform.getRepoStatus.mockResolvedValueOnce({
         modified: ['Gemfile.lock'],
diff --git a/test/manager/cargo/artifacts.spec.ts b/test/manager/cargo/artifacts.spec.ts
index b874a2186572fbf2bbf20b62273d7639c295e7b8..87ca206e3071443d67a92e97018a1a6a54d241de 100644
--- a/test/manager/cargo/artifacts.spec.ts
+++ b/test/manager/cargo/artifacts.spec.ts
@@ -1,13 +1,15 @@
 import _fs from 'fs-extra';
+import { exec as _exec } from 'child_process';
 import * as cargo from '../../../lib/manager/cargo/artifacts';
 import { platform as _platform } from '../../../lib/platform';
+import { mocked } from '../../util';
 
 jest.mock('fs-extra');
-jest.mock('../../../lib/util/exec');
-const { exec } = require('../../../lib/util/exec');
+jest.mock('child_process');
 
-const platform: any = _platform;
-const fs: any = _fs;
+const fs: jest.Mocked<typeof _fs> = _fs as any;
+const exec: jest.Mock<typeof _exec> = _exec as any;
+const platform = mocked(_platform);
 
 const config = {
   localDir: '/tmp/github/some/repo',
@@ -32,24 +34,24 @@ describe('.updateArtifacts()', () => {
     ).toBeNull();
   });
   it('returns null if unchanged', async () => {
-    platform.getFile.mockReturnValueOnce('Current Cargo.lock');
-    exec.mockReturnValueOnce({
-      stdout: '',
-      stderror: '',
+    platform.getFile.mockResolvedValueOnce('Current Cargo.lock');
+    exec.mockImplementationOnce((cmd, _options, callback) => {
+      callback(null, '', '');
+      return undefined;
     });
-    fs.readFile = jest.fn(() => 'Current Cargo.lock');
+    fs.readFile.mockReturnValueOnce('Current Cargo.lock' as any);
     const updatedDeps = ['dep1'];
     expect(
       await cargo.updateArtifacts('Cargo.toml', updatedDeps, '', config)
     ).toBeNull();
   });
   it('returns updated Cargo.lock', async () => {
-    platform.getFile.mockReturnValueOnce('Old Cargo.lock');
-    exec.mockReturnValueOnce({
-      stdout: '',
-      stderror: '',
+    platform.getFile.mockResolvedValueOnce('Old Cargo.lock');
+    exec.mockImplementationOnce((cmd, _options, callback) => {
+      callback(null, '', '');
+      return undefined;
     });
-    fs.readFile = jest.fn(() => 'New Cargo.lock');
+    fs.readFile.mockReturnValueOnce('New Cargo.lock' as any);
     const updatedDeps = ['dep1'];
     global.trustLevel = 'high';
     expect(
@@ -58,15 +60,13 @@ describe('.updateArtifacts()', () => {
   });
   it('returns updated Cargo.lock with docker', async () => {
     let dockerCommand = null;
-    platform.getFile.mockReturnValueOnce('Old Cargo.lock');
-    exec.mockImplementationOnce(cmd => {
+    platform.getFile.mockResolvedValueOnce('Old Cargo.lock');
+    exec.mockImplementationOnce((cmd, _options, callback) => {
       dockerCommand = cmd;
-      return Promise.resolve({
-        stdout: '',
-        stderror: '',
-      });
+      callback(null, '', '');
+      return undefined;
     });
-    fs.readFile = jest.fn(() => 'New Cargo.lock');
+    fs.readFile.mockReturnValueOnce('New Cargo.lock' as any);
     const updatedDeps = ['dep1'];
     global.trustLevel = 'high';
     expect(
@@ -79,8 +79,8 @@ describe('.updateArtifacts()', () => {
     expect(dockerCommand.replace(/\\(\w)/g, '/$1')).toMatchSnapshot();
   });
   it('catches errors', async () => {
-    platform.getFile.mockReturnValueOnce('Current Cargo.lock');
-    fs.outputFile = jest.fn(() => {
+    platform.getFile.mockResolvedValueOnce('Current Cargo.lock');
+    fs.outputFile.mockImplementationOnce(() => {
       throw new Error('not found');
     });
     const updatedDeps = ['dep1'];
diff --git a/test/manager/composer/artifacts.spec.ts b/test/manager/composer/artifacts.spec.ts
index a962062994b3ba9a32cb67e10c21e22e0bf6f117..e087c6ed93f2a2859b70690105e8b69e5e3008c3 100644
--- a/test/manager/composer/artifacts.spec.ts
+++ b/test/manager/composer/artifacts.spec.ts
@@ -1,16 +1,19 @@
 import _fs from 'fs-extra';
+import { exec as _exec } from 'child_process';
 import * as composer from '../../../lib/manager/composer/artifacts';
 import { platform as _platform } from '../../../lib/platform';
+import { mocked } from '../../util';
+import { StatusResult } from '../../../lib/platform/git/storage';
 
 jest.mock('fs-extra');
-jest.mock('../../../lib/util/exec');
+jest.mock('child_process');
 jest.mock('../../../lib/util/host-rules');
 
-const { exec } = require('../../../lib/util/exec');
 const hostRules = require('../../../lib/util/host-rules');
 
-const platform: any = _platform;
-const fs: any = _fs;
+const fs: jest.Mocked<typeof _fs> = _fs as any;
+const exec: jest.Mock<typeof _exec> = _exec as any;
+const platform = mocked(_platform);
 
 const config = {
   localDir: '/tmp/github/some/repo',
@@ -30,24 +33,24 @@ describe('.updateArtifacts()', () => {
     ).toBeNull();
   });
   it('returns null if unchanged', async () => {
-    platform.getFile.mockReturnValueOnce('Current composer.lock');
-    exec.mockReturnValueOnce({
-      stdout: '',
-      stderror: '',
+    platform.getFile.mockResolvedValueOnce('Current composer.lock');
+    exec.mockImplementationOnce((cmd, _options, callback) => {
+      callback(null, '', '');
+      return undefined;
     });
-    fs.readFile = jest.fn(() => 'Current composer.lock');
-    platform.getRepoStatus.mockResolvedValue({ modified: [] });
+    fs.readFile.mockReturnValueOnce('Current composer.lock' as any);
+    platform.getRepoStatus.mockResolvedValue({ modified: [] } as StatusResult);
     expect(
       await composer.updateArtifacts('composer.json', [], '{}', config)
     ).toBeNull();
   });
   it('uses hostRules to write auth.json', async () => {
-    platform.getFile.mockReturnValueOnce('Current composer.lock');
-    exec.mockReturnValueOnce({
-      stdout: '',
-      stderror: '',
+    platform.getFile.mockResolvedValueOnce('Current composer.lock');
+    exec.mockImplementationOnce((cmd, _options, callback) => {
+      callback(null, '', '');
+      return undefined;
     });
-    fs.readFile = jest.fn(() => 'Current composer.lock');
+    fs.readFile.mockReturnValueOnce('Current composer.lock' as any);
     const authConfig = {
       localDir: '/tmp/github/some/repo',
       registryUrls: ['https://packagist.renovatebot.com'],
@@ -56,32 +59,36 @@ describe('.updateArtifacts()', () => {
       username: 'some-username',
       password: 'some-password',
     });
-    platform.getRepoStatus.mockResolvedValue({ modified: [] });
+    platform.getRepoStatus.mockResolvedValue({ modified: [] } as StatusResult);
     expect(
       await composer.updateArtifacts('composer.json', [], '{}', authConfig)
     ).toBeNull();
   });
   it('returns updated composer.lock', async () => {
-    platform.getFile.mockReturnValueOnce('Current composer.lock');
-    exec.mockReturnValueOnce({
-      stdout: '',
-      stderror: '',
+    platform.getFile.mockResolvedValueOnce('Current composer.lock');
+    exec.mockImplementationOnce((cmd, _options, callback) => {
+      callback(null, '', '');
+      return undefined;
     });
-    fs.readFile = jest.fn(() => 'New composer.lock');
+    fs.readFile.mockReturnValueOnce('New composer.lock' as any);
     global.trustLevel = 'high';
-    platform.getRepoStatus.mockResolvedValue({ modified: ['composer.lock'] });
+    platform.getRepoStatus.mockResolvedValue({
+      modified: ['composer.lock'],
+    } as StatusResult);
     expect(
       await composer.updateArtifacts('composer.json', [], '{}', config)
     ).not.toBeNull();
   });
   it('performs lockFileMaintenance', async () => {
-    platform.getFile.mockReturnValueOnce('Current composer.lock');
-    exec.mockReturnValueOnce({
-      stdout: '',
-      stderror: '',
+    platform.getFile.mockResolvedValueOnce('Current composer.lock');
+    exec.mockImplementationOnce((cmd, _options, callback) => {
+      callback(null, '', '');
+      return undefined;
     });
-    fs.readFile = jest.fn(() => 'New composer.lock');
-    platform.getRepoStatus.mockResolvedValue({ modified: ['composer.lock'] });
+    fs.readFile.mockReturnValueOnce('New composer.lock' as any);
+    platform.getRepoStatus.mockResolvedValue({
+      modified: ['composer.lock'],
+    } as StatusResult);
     expect(
       await composer.updateArtifacts('composer.json', [], '{}', {
         ...config,
@@ -90,18 +97,16 @@ describe('.updateArtifacts()', () => {
     ).not.toBeNull();
   });
   it('supports docker mode', async () => {
-    platform.getFile.mockReturnValueOnce('Current composer.lock');
+    platform.getFile.mockResolvedValueOnce('Current composer.lock');
 
     let dockerCommand = null;
-    exec.mockImplementationOnce(cmd => {
+    exec.mockImplementationOnce((cmd, _options, callback) => {
       dockerCommand = cmd;
-      return Promise.resolve({
-        stdout: '',
-        stderror: '',
-      });
+      callback(null, '', '');
+      return undefined;
     });
 
-    fs.readFile = jest.fn(() => 'New composer.lock');
+    fs.readFile.mockReturnValueOnce('New composer.lock' as any);
     expect(
       await composer.updateArtifacts('composer.json', [], '{}', {
         ...config,
@@ -112,12 +117,12 @@ describe('.updateArtifacts()', () => {
     expect(dockerCommand.replace(/\\(\w)/g, '/$1')).toMatchSnapshot();
   });
   it('supports global mode', async () => {
-    platform.getFile.mockReturnValueOnce('Current composer.lock');
-    exec.mockReturnValueOnce({
-      stdout: '',
-      stderror: '',
+    platform.getFile.mockResolvedValueOnce('Current composer.lock');
+    exec.mockImplementationOnce((cmd, _options, callback) => {
+      callback(null, '', '');
+      return undefined;
     });
-    fs.readFile = jest.fn(() => 'New composer.lock');
+    fs.readFile.mockReturnValueOnce('New composer.lock' as any);
     expect(
       await composer.updateArtifacts('composer.json', [], '{}', {
         ...config,
@@ -126,8 +131,8 @@ describe('.updateArtifacts()', () => {
     ).not.toBeNull();
   });
   it('catches errors', async () => {
-    platform.getFile.mockReturnValueOnce('Current composer.lock');
-    fs.outputFile = jest.fn(() => {
+    platform.getFile.mockResolvedValueOnce('Current composer.lock');
+    fs.outputFile.mockImplementationOnce(() => {
       throw new Error('not found');
     });
     expect(
@@ -135,8 +140,8 @@ describe('.updateArtifacts()', () => {
     ).toMatchSnapshot();
   });
   it('catches unmet requirements errors', async () => {
-    platform.getFile.mockReturnValueOnce('Current composer.lock');
-    fs.outputFile = jest.fn(() => {
+    platform.getFile.mockResolvedValueOnce('Current composer.lock');
+    fs.outputFile.mockImplementationOnce(() => {
       throw new Error(
         'fooYour requirements could not be resolved to an installable set of packages.bar'
       );
@@ -146,8 +151,8 @@ describe('.updateArtifacts()', () => {
     ).toMatchSnapshot();
   });
   it('throws for disk space', async () => {
-    platform.getFile.mockReturnValueOnce('Current composer.lock');
-    fs.outputFile = jest.fn(() => {
+    platform.getFile.mockResolvedValueOnce('Current composer.lock');
+    fs.outputFile.mockImplementationOnce(() => {
       throw new Error(
         'vendor/composer/07fe2366/sebastianbergmann-php-code-coverage-c896779/src/Report/Html/Renderer/Template/js/d3.min.js:  write error (disk full?).  Continue? (y/n/^C) '
       );
diff --git a/test/manager/gomod/artifacts.spec.ts b/test/manager/gomod/artifacts.spec.ts
index 01ad0d26acfd60f8b785c1c95f25161154b52c5b..1f954c6656e8d82bf63dc6f09aa236ca980bc727 100644
--- a/test/manager/gomod/artifacts.spec.ts
+++ b/test/manager/gomod/artifacts.spec.ts
@@ -1,16 +1,19 @@
 import _fs from 'fs-extra';
+import { exec as _exec } from 'child_process';
 import * as gomod from '../../../lib/manager/gomod/artifacts';
 import { platform as _platform } from '../../../lib/platform';
+import { mocked } from '../../util';
+import { StatusResult } from '../../../lib/platform/git/storage';
 
 jest.mock('fs-extra');
-jest.mock('../../../lib/util/exec');
+jest.mock('child_process');
 jest.mock('../../../lib/util/host-rules');
 
-const { exec } = require('../../../lib/util/exec');
 const hostRules = require('../../../lib/util/host-rules');
 
-const fs: any = _fs;
-const platform: any = _platform;
+const fs: jest.Mocked<typeof _fs> = _fs as any;
+const exec: jest.Mock<typeof _exec> = _exec as any;
+const platform = mocked(_platform);
 
 const gomod1 = `module github.com/renovate-tests/gomod1
 
@@ -32,9 +35,9 @@ const config = {
 describe('.updateArtifacts()', () => {
   beforeEach(() => {
     jest.resetAllMocks();
-    exec.mockResolvedValue({
-      stdout: '',
-      stderror: '',
+    exec.mockImplementation((_cmd, _options, callback) => {
+      callback(null, '', '');
+      return undefined;
     });
   });
   it('returns if no go.sum found', async () => {
@@ -43,40 +46,44 @@ describe('.updateArtifacts()', () => {
     ).toBeNull();
   });
   it('returns null if unchanged', async () => {
-    platform.getFile.mockReturnValueOnce('Current go.sum');
-    exec.mockReturnValueOnce({
-      stdout: '',
-      stderror: '',
+    platform.getFile.mockResolvedValueOnce('Current go.sum');
+    exec.mockImplementationOnce((_cmd, _options, callback) => {
+      callback(null, '', '');
+      return undefined;
     });
-    platform.getRepoStatus.mockResolvedValue({ modified: [] });
+    platform.getRepoStatus.mockResolvedValueOnce({
+      modified: [],
+    } as StatusResult);
     expect(
       await gomod.updateArtifacts('go.mod', [], gomod1, config)
     ).toBeNull();
   });
   it('returns updated go.sum', async () => {
-    platform.getFile.mockReturnValueOnce('Current go.sum');
-    exec.mockReturnValueOnce({
-      stdout: '',
-      stderror: '',
+    platform.getFile.mockResolvedValueOnce('Current go.sum');
+    exec.mockImplementationOnce((_cmd, _options, callback) => {
+      callback(null, '', '');
+      return undefined;
     });
-    platform.getRepoStatus.mockResolvedValue({ modified: ['go.sum'] });
-    fs.readFile = jest.fn(() => 'New go.sum');
+    platform.getRepoStatus.mockResolvedValueOnce({
+      modified: ['go.sum'],
+    } as StatusResult);
+    fs.readFile.mockReturnValueOnce('New go.sum' as any);
     expect(
       await gomod.updateArtifacts('go.mod', [], gomod1, config)
     ).not.toBeNull();
   });
   it('supports docker mode without credentials', async () => {
-    platform.getFile.mockReturnValueOnce('Current go.sum');
+    platform.getFile.mockResolvedValueOnce('Current go.sum');
     let dockerCommand = null;
-    exec.mockImplementationOnce(cmd => {
+    exec.mockImplementationOnce((cmd, _options, callback) => {
       dockerCommand = cmd;
-      return Promise.resolve({
-        stdout: '',
-        stderror: '',
-      });
+      callback(null, '', '');
+      return undefined;
     });
-    platform.getRepoStatus.mockResolvedValue({ modified: ['go.sum'] });
-    fs.readFile = jest.fn(() => 'New go.sum');
+    platform.getRepoStatus.mockResolvedValueOnce({
+      modified: ['go.sum'],
+    } as StatusResult);
+    fs.readFile.mockReturnValueOnce('New go.sum' as any);
     expect(
       await gomod.updateArtifacts('go.mod', [], gomod1, {
         ...config,
@@ -87,13 +94,15 @@ describe('.updateArtifacts()', () => {
     expect(dockerCommand.replace(/\\(\w)/g, '/$1')).toMatchSnapshot();
   });
   it('supports global mode', async () => {
-    platform.getFile.mockReturnValueOnce('Current go.sum');
-    exec.mockReturnValueOnce({
-      stdout: '',
-      stderror: '',
+    platform.getFile.mockResolvedValueOnce('Current go.sum');
+    exec.mockImplementationOnce((cmd, _options, callback) => {
+      callback(null, '', '');
+      return undefined;
     });
-    platform.getRepoStatus.mockResolvedValue({ modified: ['go.sum'] });
-    fs.readFile = jest.fn(() => 'New go.sum');
+    platform.getRepoStatus.mockResolvedValueOnce({
+      modified: ['go.sum'],
+    } as StatusResult);
+    fs.readFile.mockReturnValueOnce('New go.sum' as any);
     expect(
       await gomod.updateArtifacts('go.mod', [], gomod1, {
         ...config,
@@ -102,20 +111,20 @@ describe('.updateArtifacts()', () => {
     ).not.toBeNull();
   });
   it('supports docker mode with credentials', async () => {
-    hostRules.find.mockReturnValue({
+    hostRules.find.mockReturnValueOnce({
       token: 'some-token',
     });
-    platform.getFile.mockReturnValueOnce('Current go.sum');
+    platform.getFile.mockResolvedValueOnce('Current go.sum');
     let dockerCommand = null;
-    exec.mockImplementationOnce(cmd => {
+    exec.mockImplementationOnce((cmd, _options, callback) => {
       dockerCommand = cmd;
-      return Promise.resolve({
-        stdout: '',
-        stderror: '',
-      });
+      callback(null, '', '');
+      return undefined;
     });
-    platform.getRepoStatus.mockResolvedValue({ modified: ['go.sum'] });
-    fs.readFile = jest.fn(() => 'New go.sum');
+    platform.getRepoStatus.mockResolvedValueOnce({
+      modified: ['go.sum'],
+    } as StatusResult);
+    fs.readFile.mockReturnValueOnce('New go.sum' as any);
     expect(
       await gomod.updateArtifacts('go.mod', [], gomod1, {
         ...config,
@@ -125,22 +134,22 @@ describe('.updateArtifacts()', () => {
     expect(dockerCommand.replace(/\\(\w)/g, '/$1')).toMatchSnapshot();
   });
   it('supports docker mode with credentials, appMode and trustLevel=high', async () => {
-    hostRules.find.mockReturnValue({
+    hostRules.find.mockReturnValueOnce({
       token: 'some-token',
     });
     platform.getFile.mockResolvedValueOnce('Current go.sum');
     let dockerCommand = null;
-    exec.mockImplementationOnce(cmd => {
+    exec.mockImplementationOnce((cmd, _options, callback) => {
       dockerCommand = cmd;
-      return Promise.resolve({
-        stdout: '',
-        stderror: '',
-      });
+      callback(null, '', '');
+      return undefined;
     });
-    platform.getRepoStatus.mockResolvedValue({ modified: ['go.sum'] });
-    fs.readFile.mockResolvedValue('New go.sum 1');
-    fs.readFile.mockResolvedValue('New go.sum 2');
-    fs.readFile.mockResolvedValue('New go.sum 3');
+    platform.getRepoStatus.mockResolvedValueOnce({
+      modified: ['go.sum'],
+    } as StatusResult);
+    fs.readFile.mockResolvedValueOnce('New go.sum 1' as any);
+    fs.readFile.mockResolvedValueOnce('New go.sum 2' as any);
+    fs.readFile.mockResolvedValueOnce('New go.sum 3' as any);
     try {
       global.appMode = true;
       global.trustLevel = 'high';
@@ -158,8 +167,8 @@ describe('.updateArtifacts()', () => {
     }
   });
   it('catches errors', async () => {
-    platform.getFile.mockReturnValueOnce('Current go.sum');
-    fs.outputFile = jest.fn(() => {
+    platform.getFile.mockResolvedValueOnce('Current go.sum');
+    fs.outputFile.mockImplementationOnce(() => {
       throw new Error('This update totally doesnt work');
     });
     expect(
diff --git a/test/manager/mix/artifacts.spec.ts b/test/manager/mix/artifacts.spec.ts
index 7bcf3d187a298b251f2980621502221167fb5227..8af17ce2ecdb1fe0101180d29e79bb466a233907 100644
--- a/test/manager/mix/artifacts.spec.ts
+++ b/test/manager/mix/artifacts.spec.ts
@@ -1,14 +1,15 @@
 import _fs from 'fs-extra';
-import { exec as _exec } from '../../../lib/util/exec';
+import { exec as _exec } from 'child_process';
 import { platform as _platform } from '../../../lib/platform';
 import { updateArtifacts } from '../../../lib/manager/mix';
+import { mocked } from '../../util';
 
-const fs: any = _fs;
-const exec: any = _exec;
-const platform: any = _platform;
+const fs: jest.Mocked<typeof _fs> = _fs as any;
+const exec: jest.Mock<typeof _exec> = _exec as any;
+const platform = mocked(_platform);
 
 jest.mock('fs-extra');
-jest.mock('../../../lib/util/exec');
+jest.mock('child_process');
 jest.mock('../../../lib/platform');
 
 const config = {
@@ -37,25 +38,23 @@ describe('.updateArtifacts()', () => {
     expect(await updateArtifacts('mix.exs', ['plug'], '', config)).toBeNull();
   });
   it('returns null if unchanged', async () => {
-    platform.getFile.mockReturnValueOnce('Current mix.lock');
-    exec.mockReturnValue({
-      stdout: '',
-      stderr: '',
+    platform.getFile.mockResolvedValueOnce('Current mix.lock');
+    exec.mockImplementationOnce((cmd, _options, callback) => {
+      callback(null, '', '');
+      return undefined;
     });
-    fs.readFile.mockReturnValueOnce('Current mix.lock');
+    fs.readFile.mockResolvedValueOnce('Current mix.lock' as any);
     expect(await updateArtifacts('mix.exs', ['plug'], '', config)).toBeNull();
   });
   it('returns updated mix.lock', async () => {
-    platform.getFile.mockReturnValueOnce('Old mix.lock');
+    platform.getFile.mockResolvedValueOnce('Old mix.lock');
     let dockerCommand = null;
-    exec.mockImplementationOnce(cmd => {
+    exec.mockImplementationOnce((cmd, _options, callback) => {
       dockerCommand = cmd;
-      return Promise.resolve({
-        stdout: '',
-        stderror: '',
-      });
+      callback(null, '', '');
+      return undefined;
     });
-    fs.readFile.mockImplementationOnce(() => 'New mix.lock');
+    fs.readFile.mockResolvedValueOnce('New mix.lock' as any);
     expect(
       await updateArtifacts('mix.exs', ['plug'], '{}', {
         ...config,
@@ -65,7 +64,7 @@ describe('.updateArtifacts()', () => {
     expect(dockerCommand.replace(/\\(\w)/g, '/$1')).toMatchSnapshot();
   });
   it('catches errors', async () => {
-    platform.getFile.mockReturnValueOnce('Current mix.lock');
+    platform.getFile.mockResolvedValueOnce('Current mix.lock');
     fs.outputFile.mockImplementationOnce(() => {
       throw new Error('not found');
     });
diff --git a/test/manager/pipenv/artifacts.spec.ts b/test/manager/pipenv/artifacts.spec.ts
index a191fe7ac4741eef2fa787939f0039e80ddedc18..0649ff869e06b323dce4ef6c14de776fef83d382 100644
--- a/test/manager/pipenv/artifacts.spec.ts
+++ b/test/manager/pipenv/artifacts.spec.ts
@@ -1,16 +1,17 @@
 import _fs from 'fs-extra';
-import { exec as _exec } from '../../../lib/util/exec';
+import { exec as _exec } from 'child_process';
 import * as pipenv from '../../../lib/manager/pipenv/artifacts';
 import { platform as _platform } from '../../../lib/platform';
+import { mocked } from '../../util';
+import { StatusResult } from '../../../lib/platform/git/storage';
 
 jest.mock('fs-extra');
-jest.mock('../../../lib/util/exec');
+jest.mock('child_process');
 jest.mock('../../../lib/util/host-rules');
 
-const fs: any = _fs;
-const exec: any = _exec;
-
-const platform: any = _platform;
+const fs: jest.Mocked<typeof _fs> = _fs as any;
+const exec: jest.Mock<typeof _exec> = _exec as any;
+const platform = mocked(_platform);
 
 const config = {
   localDir: '/tmp/github/some/repo',
@@ -28,41 +29,43 @@ describe('.updateArtifacts()', () => {
     expect(await pipenv.updateArtifacts('Pipfile', [], '', config)).toBeNull();
   });
   it('returns null if unchanged', async () => {
-    platform.getFile.mockReturnValueOnce('Current Pipfile.lock');
-    exec.mockReturnValueOnce({
-      stdout: 'Locking',
-      stderror: '',
+    platform.getFile.mockResolvedValueOnce('Current Pipfile.lock');
+    exec.mockImplementationOnce((cmd, _options, callback) => {
+      callback(null, '', '');
+      return undefined;
     });
-    fs.readFile = jest.fn(() => 'Current Pipfile.lock');
+    fs.readFile.mockReturnValueOnce('Current Pipfile.lock' as any);
     expect(
       await pipenv.updateArtifacts('Pipfile', [], '{}', config)
     ).toBeNull();
   });
   it('returns updated Pipfile.lock', async () => {
-    platform.getFile.mockReturnValueOnce('Current Pipfile.lock');
-    exec.mockReturnValueOnce({
-      stdout: '',
-      stderror: '',
+    platform.getFile.mockResolvedValueOnce('Current Pipfile.lock');
+    exec.mockImplementationOnce((cmd, _options, callback) => {
+      callback(null, '', '');
+      return undefined;
     });
-    platform.getRepoStatus.mockResolvedValue({ modified: ['Pipfile.lock'] });
-    fs.readFile = jest.fn(() => 'New Pipfile.lock');
+    platform.getRepoStatus.mockResolvedValue({
+      modified: ['Pipfile.lock'],
+    } as StatusResult);
+    fs.readFile.mockReturnValueOnce('New Pipfile.lock' as any);
     global.trustLevel = 'high';
     expect(
       await pipenv.updateArtifacts('Pipfile', [], '{}', config)
     ).not.toBeNull();
   });
   it('supports docker mode', async () => {
-    platform.getFile.mockReturnValueOnce('Current Pipfile.lock');
+    platform.getFile.mockResolvedValueOnce('Current Pipfile.lock');
     let dockerCommand = null;
-    exec.mockImplementationOnce(cmd => {
+    exec.mockImplementationOnce((cmd, _options, callback) => {
       dockerCommand = cmd;
-      return Promise.resolve({
-        stdout: '',
-        stderror: '',
-      });
+      callback(null, '', '');
+      return undefined;
     });
-    platform.getRepoStatus.mockResolvedValue({ modified: ['Pipfile.lock'] });
-    fs.readFile = jest.fn(() => 'New Pipfile.lock');
+    platform.getRepoStatus.mockResolvedValue({
+      modified: ['Pipfile.lock'],
+    } as StatusResult);
+    fs.readFile.mockReturnValueOnce('New Pipfile.lock' as any);
     expect(
       await pipenv.updateArtifacts('Pipfile', [], '{}', {
         ...config,
@@ -73,8 +76,8 @@ describe('.updateArtifacts()', () => {
     expect(dockerCommand.replace(/\\(\w)/g, '/$1')).toMatchSnapshot();
   });
   it('catches errors', async () => {
-    platform.getFile.mockReturnValueOnce('Current Pipfile.lock');
-    fs.outputFile = jest.fn(() => {
+    platform.getFile.mockResolvedValueOnce('Current Pipfile.lock');
+    fs.outputFile.mockImplementationOnce(() => {
       throw new Error('not found');
     });
     expect(
diff --git a/test/manager/poetry/artifacts.spec.ts b/test/manager/poetry/artifacts.spec.ts
index ca5ec0c44f9163078a464c8708ff7a7b74fd7811..78d8cc8a07e7677a02722bdc5e76f09995ad7703 100644
--- a/test/manager/poetry/artifacts.spec.ts
+++ b/test/manager/poetry/artifacts.spec.ts
@@ -1,14 +1,15 @@
 import _fs from 'fs-extra';
-import { exec as _exec } from '../../../lib/util/exec';
+import { exec as _exec } from 'child_process';
 import { updateArtifacts } from '../../../lib/manager/poetry/artifacts';
 import { platform as _platform } from '../../../lib/platform';
+import { mocked } from '../../util';
 
 jest.mock('fs-extra');
-jest.mock('../../../lib/util/exec');
+jest.mock('child_process');
 
-const platform: any = _platform;
-const exec: any = _exec;
-const fs: any = _fs;
+const fs: jest.Mocked<typeof _fs> = _fs as any;
+const exec: jest.Mock<typeof _exec> = _exec as any;
+const platform = mocked(_platform);
 
 const config = {
   localDir: '/tmp/github/some/repo',
@@ -31,24 +32,24 @@ describe('.updateArtifacts()', () => {
     expect(await updateArtifacts('pyproject.toml', [], '', config)).toBeNull();
   });
   it('returns null if unchanged', async () => {
-    platform.getFile.mockReturnValueOnce('Current poetry.lock');
-    exec.mockReturnValueOnce({
-      stdout: '',
-      stderror: '',
+    platform.getFile.mockResolvedValueOnce('Current poetry.lock');
+    exec.mockImplementationOnce((cmd, _options, callback) => {
+      callback(null, '', '');
+      return undefined;
     });
-    fs.readFile = jest.fn(() => 'Current poetry.lock');
+    fs.readFile.mockReturnValueOnce('Current poetry.lock' as any);
     const updatedDeps = ['dep1'];
     expect(
       await updateArtifacts('pyproject.toml', updatedDeps, '', config)
     ).toBeNull();
   });
   it('returns updated poetry.lock', async () => {
-    platform.getFile.mockReturnValueOnce('Old poetry.lock');
-    exec.mockReturnValueOnce({
-      stdout: '',
-      stderror: '',
+    platform.getFile.mockResolvedValueOnce('Old poetry.lock');
+    exec.mockImplementationOnce((cmd, _options, callback) => {
+      callback(null, '', '');
+      return undefined;
     });
-    fs.readFile = jest.fn(() => 'New poetry.lock');
+    fs.readFile.mockReturnValueOnce('New poetry.lock' as any);
     const updatedDeps = ['dep1'];
     global.trustLevel = 'high';
     expect(
@@ -56,16 +57,14 @@ describe('.updateArtifacts()', () => {
     ).not.toBeNull();
   });
   it('returns updated poetry.lock using docker', async () => {
-    platform.getFile.mockReturnValueOnce('Old poetry.lock');
+    platform.getFile.mockResolvedValueOnce('Old poetry.lock');
     let dockerCommand = null;
-    exec.mockImplementationOnce(cmd => {
+    exec.mockImplementationOnce((cmd, _options, callback) => {
       dockerCommand = cmd;
-      return Promise.resolve({
-        stdout: '',
-        stderror: '',
-      });
+      callback(null, '', '');
+      return undefined;
     });
-    fs.readFile = jest.fn(() => 'New poetry.lock');
+    fs.readFile.mockReturnValueOnce('New poetry.lock' as any);
     const updatedDeps = ['dep1'];
     global.trustLevel = 'high';
     expect(
@@ -78,8 +77,8 @@ describe('.updateArtifacts()', () => {
     expect(dockerCommand.replace(/\\(\w)/g, '/$1')).toMatchSnapshot();
   });
   it('catches errors', async () => {
-    platform.getFile.mockReturnValueOnce('Current poetry.lock');
-    fs.outputFile = jest.fn(() => {
+    platform.getFile.mockResolvedValueOnce('Current poetry.lock');
+    fs.outputFile.mockImplementationOnce(() => {
       throw new Error('not found');
     });
     const updatedDeps = ['dep1'];