diff --git a/lib/manager/npm/post-update/index.ts b/lib/manager/npm/post-update/index.ts
index e40b103529d03a1bb6e199ceb75c657087fb9b25..6207c66889aaa5ac7a7236d1fcd13e95f44c9212 100644
--- a/lib/manager/npm/post-update/index.ts
+++ b/lib/manager/npm/post-update/index.ts
@@ -541,7 +541,7 @@ export async function getAdditionalFiles(
       (upgrade) => upgrade.npmLock === npmLock
     );
     const res = await npm.generateLockFile(
-      lockFileDir,
+      fullLockFileDir,
       env,
       fileName,
       config,
diff --git a/lib/manager/npm/post-update/lerna.ts b/lib/manager/npm/post-update/lerna.ts
index ebd4cddb00c21139839e55cddb15a39c48409d26..776b4c75c70f4f9ad68ed66151c871fc77337898 100644
--- a/lib/manager/npm/post-update/lerna.ts
+++ b/lib/manager/npm/post-update/lerna.ts
@@ -26,7 +26,7 @@ export function getLernaVersion(
 
 export async function generateLockFiles(
   lernaPackageFile: Partial<PackageFile>,
-  lockFileDir: string,
+  cwd: string,
   config: PostUpdateConfig,
   env: NodeJS.ProcessEnv,
   skipInstalls?: boolean
@@ -75,7 +75,7 @@ export async function generateLockFiles(
     lernaCommand += cmdOptions;
     const tagConstraint = await getNodeConstraint(config);
     const execOptions: ExecOptions = {
-      cwd: lockFileDir,
+      cwd,
       extraEnv: {
         NPM_CONFIG_CACHE: env.NPM_CONFIG_CACHE,
         npm_config_store: env.npm_config_store,
diff --git a/lib/manager/npm/post-update/npm.spec.ts b/lib/manager/npm/post-update/npm.spec.ts
index 7ba640af365772651f7003aa4d36d8b316fcac2c..e4f9341151427be2b7b907f2b7f5a208fc1b8552 100644
--- a/lib/manager/npm/post-update/npm.spec.ts
+++ b/lib/manager/npm/post-update/npm.spec.ts
@@ -1,25 +1,30 @@
+import { exec as _exec } from 'child_process';
 import upath from 'upath';
-import { envMock, exec, mockExecAll } from '../../../../test/exec-util';
-import { env, fs } from '../../../../test/util';
-import { GlobalConfig } from '../../../config/global';
+
+import { envMock, mockExecAll } from '../../../../test/exec-util';
+import { mocked } from '../../../../test/util';
+import * as _env from '../../../util/exec/env';
+import * as _fs from '../../../util/fs/proxies';
 import * as npmHelper from './npm';
 
 jest.mock('child_process');
 jest.mock('../../../util/exec/env');
-jest.mock('../../../util/fs');
+jest.mock('../../../util/fs/proxies');
 jest.mock('./node-version');
 
+const exec: jest.Mock<typeof _exec> = _exec as any;
+const env = mocked(_env);
+const fs = mocked(_fs);
+
 describe('manager/npm/post-update/npm', () => {
   beforeEach(() => {
     jest.resetAllMocks();
     jest.resetModules();
     env.getChildProcessEnv.mockReturnValue(envMock.basic);
-    GlobalConfig.set({ localDir: '' });
   });
-
   it('generates lock files', async () => {
     const execSnapshots = mockExecAll(exec);
-    fs.readLocalFile.mockResolvedValueOnce('package-lock-contents');
+    fs.readFile = jest.fn(() => 'package-lock-contents') as never;
     const skipInstalls = true;
     const postUpdateOptions = ['npmDedupe'];
     const updates = [
@@ -32,15 +37,14 @@ describe('manager/npm/post-update/npm', () => {
       { skipInstalls, postUpdateOptions },
       updates
     );
-    expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
+    expect(fs.readFile).toHaveBeenCalledTimes(1);
     expect(res.error).toBeUndefined();
     expect(res.lockFile).toBe('package-lock-contents');
     expect(execSnapshots).toMatchSnapshot();
   });
-
   it('performs lock file updates', async () => {
     const execSnapshots = mockExecAll(exec);
-    fs.readLocalFile.mockResolvedValueOnce('package-lock-contents');
+    fs.readFile = jest.fn(() => 'package-lock-contents') as never;
     const skipInstalls = true;
     const updates = [
       { depName: 'some-dep', newVersion: '1.0.1', isLockfileUpdate: true },
@@ -52,16 +56,16 @@ describe('manager/npm/post-update/npm', () => {
       { skipInstalls },
       updates
     );
-    expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
+    expect(fs.readFile).toHaveBeenCalledTimes(1);
     expect(res.error).toBeUndefined();
     expect(res.lockFile).toBe('package-lock-contents');
     expect(execSnapshots).toMatchSnapshot();
   });
-
   it('performs npm-shrinkwrap.json updates', async () => {
     const execSnapshots = mockExecAll(exec);
-    fs.localPathExists.mockResolvedValueOnce(true);
-    fs.readLocalFile.mockResolvedValueOnce('package-lock-contents');
+    fs.pathExists.mockResolvedValueOnce(true);
+    fs.move = jest.fn();
+    fs.readFile = jest.fn(() => 'package-lock-contents') as never;
     const skipInstalls = true;
     const res = await npmHelper.generateLockFile(
       'some-dir',
@@ -69,25 +73,28 @@ describe('manager/npm/post-update/npm', () => {
       'npm-shrinkwrap.json',
       { skipInstalls }
     );
+    expect(fs.pathExists).toHaveBeenCalledWith(
+      upath.join('some-dir', 'package-lock.json')
+    );
     expect(fs.move).toHaveBeenCalledTimes(1);
     expect(fs.move).toHaveBeenCalledWith(
       upath.join('some-dir', 'package-lock.json'),
       upath.join('some-dir', 'npm-shrinkwrap.json')
     );
-    expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
-    expect(fs.readLocalFile).toHaveBeenCalledWith(
-      'some-dir/npm-shrinkwrap.json',
+    expect(fs.readFile).toHaveBeenCalledTimes(1);
+    expect(fs.readFile).toHaveBeenCalledWith(
+      upath.join('some-dir', 'npm-shrinkwrap.json'),
       'utf8'
     );
     expect(res.error).toBeUndefined();
     expect(res.lockFile).toBe('package-lock-contents');
     expect(execSnapshots).toMatchSnapshot();
   });
-
   it('performs npm-shrinkwrap.json updates (no package-lock.json)', async () => {
     const execSnapshots = mockExecAll(exec);
-    fs.findLocalSiblingOrParent.mockResolvedValueOnce(null);
-    fs.readLocalFile.mockResolvedValueOnce('package-lock-contents');
+    fs.pathExists.mockResolvedValueOnce(false);
+    fs.move = jest.fn();
+    fs.readFile = jest.fn((_, _1) => 'package-lock-contents') as never;
     const skipInstalls = true;
     const res = await npmHelper.generateLockFile(
       'some-dir',
@@ -95,20 +102,22 @@ describe('manager/npm/post-update/npm', () => {
       'npm-shrinkwrap.json',
       { skipInstalls }
     );
+    expect(fs.pathExists).toHaveBeenCalledWith(
+      upath.join('some-dir', 'package-lock.json')
+    );
     expect(fs.move).toHaveBeenCalledTimes(0);
-    expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
-    expect(fs.readLocalFile).toHaveBeenCalledWith(
-      'some-dir/npm-shrinkwrap.json',
+    expect(fs.readFile).toHaveBeenCalledTimes(1);
+    expect(fs.readFile).toHaveBeenCalledWith(
+      upath.join('some-dir', 'npm-shrinkwrap.json'),
       'utf8'
     );
     expect(res.error).toBeUndefined();
     expect(res.lockFile).toBe('package-lock-contents');
     expect(execSnapshots).toMatchSnapshot();
   });
-
   it('performs full install', async () => {
     const execSnapshots = mockExecAll(exec);
-    fs.readLocalFile.mockResolvedValueOnce('package-lock-contents');
+    fs.readFile = jest.fn(() => 'package-lock-contents') as never;
     const skipInstalls = false;
     const binarySource = 'global';
     const res = await npmHelper.generateLockFile(
@@ -117,15 +126,14 @@ describe('manager/npm/post-update/npm', () => {
       'package-lock.json',
       { skipInstalls, binarySource }
     );
-    expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
+    expect(fs.readFile).toHaveBeenCalledTimes(1);
     expect(res.error).toBeUndefined();
     expect(res.lockFile).toBe('package-lock-contents');
     expect(execSnapshots).toMatchSnapshot();
   });
-
   it('runs twice if remediating', async () => {
     const execSnapshots = mockExecAll(exec);
-    fs.readLocalFile.mockResolvedValueOnce('package-lock-contents');
+    fs.readFile = jest.fn(() => 'package-lock-contents') as never;
     const binarySource = 'global';
     const res = await npmHelper.generateLockFile(
       'some-dir',
@@ -134,58 +142,54 @@ describe('manager/npm/post-update/npm', () => {
       { binarySource },
       [{ isRemediation: true }]
     );
-    expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
+    expect(fs.readFile).toHaveBeenCalledTimes(1);
     expect(res.error).toBeUndefined();
     expect(res.lockFile).toBe('package-lock-contents');
     expect(execSnapshots).toHaveLength(2);
   });
-
   it('catches errors', async () => {
     const execSnapshots = mockExecAll(exec);
-    fs.readLocalFile.mockImplementation(() => {
+    fs.readFile = jest.fn(() => {
       throw new Error('not found');
-    });
+    }) as never;
     const res = await npmHelper.generateLockFile(
       'some-dir',
       {},
       'package-lock.json'
     );
-    expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
+    expect(fs.readFile).toHaveBeenCalledTimes(1);
     expect(res.error).toBeTrue();
     expect(res.lockFile).toBeUndefined();
     expect(execSnapshots).toMatchSnapshot();
   });
-
   it('finds npm globally', async () => {
     const execSnapshots = mockExecAll(exec);
-    fs.readLocalFile.mockResolvedValue('package-lock-contents');
+    fs.readFile = jest.fn(() => 'package-lock-contents') as never;
     const res = await npmHelper.generateLockFile(
       'some-dir',
       {},
       'package-lock.json'
     );
-    expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
+    expect(fs.readFile).toHaveBeenCalledTimes(1);
     expect(res.lockFile).toBe('package-lock-contents');
     expect(execSnapshots).toMatchSnapshot();
   });
-
   it('uses docker npm', async () => {
     const execSnapshots = mockExecAll(exec);
-    fs.readLocalFile.mockResolvedValue('package-lock-contents');
+    fs.readFile = jest.fn(() => 'package-lock-contents') as never;
     const res = await npmHelper.generateLockFile(
       'some-dir',
       {},
       'package-lock.json',
       { binarySource: 'docker', constraints: { npm: '^6.0.0' } }
     );
-    expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
+    expect(fs.readFile).toHaveBeenCalledTimes(1);
     expect(res.lockFile).toBe('package-lock-contents');
     expect(execSnapshots).toMatchSnapshot();
   });
-
   it('performs lock file maintenance', async () => {
     const execSnapshots = mockExecAll(exec);
-    fs.readLocalFile.mockResolvedValue('package-lock-contents');
+    fs.readFile = jest.fn(() => 'package-lock-contents') as never;
     const res = await npmHelper.generateLockFile(
       'some-dir',
       {},
@@ -193,8 +197,8 @@ describe('manager/npm/post-update/npm', () => {
       {},
       [{ isLockFileMaintenance: true }]
     );
-    expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
-    expect(fs.deleteLocalFile).toHaveBeenCalledTimes(1);
+    expect(fs.readFile).toHaveBeenCalledTimes(1);
+    expect(fs.remove).toHaveBeenCalledTimes(1);
     expect(res.lockFile).toBe('package-lock-contents');
     expect(execSnapshots).toMatchSnapshot();
   });
diff --git a/lib/manager/npm/post-update/npm.ts b/lib/manager/npm/post-update/npm.ts
index 1e1e4740e29d46de0d612121bde3cbe49b38bd96..f13a4f1b3cf42298a474251495f42c109b19a59e 100644
--- a/lib/manager/npm/post-update/npm.ts
+++ b/lib/manager/npm/post-update/npm.ts
@@ -7,27 +7,19 @@ import {
 import { logger } from '../../../logger';
 import { exec } from '../../../util/exec';
 import type { ExecOptions, ToolConstraint } from '../../../util/exec/types';
-import {
-  deleteLocalFile,
-  localPathExists,
-  move,
-  readLocalFile,
-} from '../../../util/fs';
+import { move, pathExists, readFile, remove } from '../../../util/fs';
 import type { PostUpdateConfig, Upgrade } from '../../types';
 import { getNodeConstraint } from './node-version';
 import type { GenerateLockFileResult } from './types';
 
 export async function generateLockFile(
-  lockFileDir: string,
+  cwd: string,
   env: NodeJS.ProcessEnv,
-  fileName: string,
+  filename: string,
   config: PostUpdateConfig = {},
   upgrades: Upgrade[] = []
 ): Promise<GenerateLockFileResult> {
-  // TODO: don't assume package-lock.json is in the same directory
-  const lockFileName = upath.join(lockFileDir, fileName);
-
-  logger.debug(`Spawning npm install to create ${lockFileDir}/${fileName}`);
+  logger.debug(`Spawning npm install to create ${cwd}/${filename}`);
   const { skipInstalls, postUpdateOptions } = config;
 
   let lockFile = null;
@@ -52,7 +44,7 @@ export async function generateLockFile(
 
     const tagConstraint = await getNodeConstraint(config);
     const execOptions: ExecOptions = {
-      cwdFile: lockFileName,
+      cwd,
       extraEnv: {
         NPM_CONFIG_CACHE: env.NPM_CONFIG_CACHE,
         npm_config_store: env.npm_config_store,
@@ -98,12 +90,15 @@ export async function generateLockFile(
       commands.push('npm dedupe');
     }
 
+    // TODO: don't assume package-lock.json is in the same directory
+    const lockFileName = upath.join(cwd, filename);
+
     if (upgrades.find((upgrade) => upgrade.isLockFileMaintenance)) {
       logger.debug(
         `Removing ${lockFileName} first due to lock file maintenance upgrade`
       );
       try {
-        await deleteLocalFile(lockFileName);
+        await remove(lockFileName);
       } catch (err) /* istanbul ignore next */ {
         logger.debug(
           { err, lockFileName },
@@ -117,17 +112,17 @@ export async function generateLockFile(
 
     // massage to shrinkwrap if necessary
     if (
-      fileName === 'npm-shrinkwrap.json' &&
-      (await localPathExists(upath.join(lockFileDir, 'package-lock.json')))
+      filename === 'npm-shrinkwrap.json' &&
+      (await pathExists(upath.join(cwd, 'package-lock.json')))
     ) {
       await move(
-        upath.join(lockFileDir, 'package-lock.json'),
-        upath.join(lockFileDir, 'npm-shrinkwrap.json')
+        upath.join(cwd, 'package-lock.json'),
+        upath.join(cwd, 'npm-shrinkwrap.json')
       );
     }
 
     // Read the result
-    lockFile = await readLocalFile(lockFileName, 'utf8');
+    lockFile = await readFile(upath.join(cwd, filename), 'utf8');
   } catch (err) /* istanbul ignore next */ {
     if (err.message === TEMPORARY_ERROR) {
       throw err;
diff --git a/lib/manager/npm/post-update/pnpm.spec.ts b/lib/manager/npm/post-update/pnpm.spec.ts
index 6b484acbb8278c6dddb32b4a40ec1317d7ad4756..14c46e2dcac12296151820474bb35a949c233274 100644
--- a/lib/manager/npm/post-update/pnpm.spec.ts
+++ b/lib/manager/npm/post-update/pnpm.spec.ts
@@ -1,69 +1,70 @@
-import { envMock, exec, mockExecAll } from '../../../../test/exec-util';
-import { env, fs, mocked } from '../../../../test/util';
-import { GlobalConfig } from '../../../config/global';
+import { exec as _exec } from 'child_process';
+import { envMock, mockExecAll } from '../../../../test/exec-util';
+import { mocked } from '../../../../test/util';
+import * as _env from '../../../util/exec/env';
+import * as _fs from '../../../util/fs/proxies';
 import type { PostUpdateConfig } from '../../types';
 import * as _pnpmHelper from './pnpm';
 
 jest.mock('child_process');
 jest.mock('../../../util/exec/env');
-jest.mock('../../../util/fs');
+jest.mock('../../../util/fs/proxies');
 jest.mock('./node-version');
 
+const exec: jest.Mock<typeof _exec> = _exec as any;
+const env = mocked(_env);
+const fs = mocked(_fs);
 const pnpmHelper = mocked(_pnpmHelper);
 delete process.env.NPM_CONFIG_CACHE;
 
 describe('manager/npm/post-update/pnpm', () => {
   let config: PostUpdateConfig;
   beforeEach(() => {
-    jest.clearAllMocks();
     config = { cacheDir: 'some-cache-dir', constraints: { pnpm: '^2.0.0' } };
     env.getChildProcessEnv.mockReturnValue(envMock.basic);
-    GlobalConfig.set({ localDir: '' });
   });
-
   it('generates lock files', async () => {
     const execSnapshots = mockExecAll(exec);
-    fs.readLocalFile.mockResolvedValueOnce('package-lock-contents');
+    fs.readFile = jest.fn(() => 'package-lock-contents') as never;
     const res = await pnpmHelper.generateLockFile('some-dir', {}, config);
-    expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
+    expect(fs.readFile).toHaveBeenCalledTimes(1);
     expect(res.lockFile).toBe('package-lock-contents');
     expect(execSnapshots).toMatchSnapshot();
   });
-
   it('catches errors', async () => {
     const execSnapshots = mockExecAll(exec);
-    fs.readLocalFile.mockRejectedValue(new Error('not found'));
+    fs.readFile = jest.fn(() => {
+      throw new Error('not found');
+    }) as never;
     const res = await pnpmHelper.generateLockFile('some-dir', {}, config);
-    expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
+    expect(fs.readFile).toHaveBeenCalledTimes(1);
     expect(res.error).toBeTrue();
     expect(res.lockFile).toBeUndefined();
     expect(execSnapshots).toMatchSnapshot();
   });
-
   it('finds pnpm globally', async () => {
     const execSnapshots = mockExecAll(exec);
-    fs.readLocalFile.mockResolvedValueOnce('package-lock-contents');
+    fs.readFile = jest.fn(() => 'package-lock-contents') as never;
     const res = await pnpmHelper.generateLockFile('some-dir', {}, config);
-    expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
+    expect(fs.readFile).toHaveBeenCalledTimes(1);
     expect(res.lockFile).toBe('package-lock-contents');
     expect(execSnapshots).toMatchSnapshot();
   });
-
   it('performs lock file maintenance', async () => {
     const execSnapshots = mockExecAll(exec);
-    fs.readLocalFile.mockResolvedValueOnce('package-lock-contents');
+    fs.readFile = jest.fn(() => 'package-lock-contents') as never;
     const res = await pnpmHelper.generateLockFile('some-dir', {}, config, [
       { isLockFileMaintenance: true },
     ]);
-    expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
-    expect(fs.deleteLocalFile).toHaveBeenCalledTimes(1);
+    expect(fs.readFile).toHaveBeenCalledTimes(1);
+    expect(fs.remove).toHaveBeenCalledTimes(1);
     expect(res.lockFile).toBe('package-lock-contents');
     expect(execSnapshots).toMatchSnapshot();
   });
 
   it('uses the new version if packageManager is updated', async () => {
     const execSnapshots = mockExecAll(exec);
-    fs.readLocalFile.mockResolvedValueOnce('package-lock-contents');
+    fs.readFile = jest.fn(() => 'package-lock-contents') as never;
     const res = await pnpmHelper.generateLockFile('some-dir', {}, config, [
       {
         depType: 'packageManager',
@@ -71,7 +72,7 @@ describe('manager/npm/post-update/pnpm', () => {
         newValue: '6.16.1',
       },
     ]);
-    expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
+    expect(fs.readFile).toHaveBeenCalledTimes(1);
     expect(res.lockFile).toBe('package-lock-contents');
     expect(execSnapshots).toMatchSnapshot();
     // TODO: check docker preCommands
diff --git a/lib/manager/npm/post-update/pnpm.ts b/lib/manager/npm/post-update/pnpm.ts
index 2ad2ec9090af4cfc55efdcfe83027224c660e03d..20b72530a558e31ee0585d9c5e4db215d988f901 100644
--- a/lib/manager/npm/post-update/pnpm.ts
+++ b/lib/manager/npm/post-update/pnpm.ts
@@ -4,18 +4,18 @@ import { TEMPORARY_ERROR } from '../../../constants/error-messages';
 import { logger } from '../../../logger';
 import { exec } from '../../../util/exec';
 import type { ExecOptions, ToolConstraint } from '../../../util/exec/types';
-import { deleteLocalFile, readLocalFile } from '../../../util/fs';
+import { readFile, remove } from '../../../util/fs';
 import type { PostUpdateConfig, Upgrade } from '../../types';
 import { getNodeConstraint } from './node-version';
 import type { GenerateLockFileResult } from './types';
 
 export async function generateLockFile(
-  lockFileDir: string,
+  cwd: string,
   env: NodeJS.ProcessEnv,
   config: PostUpdateConfig,
   upgrades: Upgrade[] = []
 ): Promise<GenerateLockFileResult> {
-  const lockFileName = upath.join(lockFileDir, 'pnpm-lock.yaml');
+  const lockFileName = upath.join(cwd, 'pnpm-lock.yaml');
   logger.debug(`Spawning pnpm install to create ${lockFileName}`);
   let lockFile = null;
   let stdout: string;
@@ -32,7 +32,7 @@ export async function generateLockFile(
     };
     const tagConstraint = await getNodeConstraint(config);
     const execOptions: ExecOptions = {
-      cwdFile: lockFileName,
+      cwd,
       extraEnv: {
         NPM_CONFIG_CACHE: env.NPM_CONFIG_CACHE,
         npm_config_store: env.npm_config_store,
@@ -62,7 +62,7 @@ export async function generateLockFile(
         `Removing ${lockFileName} first due to lock file maintenance upgrade`
       );
       try {
-        await deleteLocalFile(lockFileName);
+        await remove(lockFileName);
       } catch (err) /* istanbul ignore next */ {
         logger.debug(
           { err, lockFileName },
@@ -72,7 +72,7 @@ export async function generateLockFile(
     }
 
     await exec(`${cmd} ${args}`, execOptions);
-    lockFile = await readLocalFile(lockFileName, 'utf8');
+    lockFile = await readFile(lockFileName, 'utf8');
   } catch (err) /* istanbul ignore next */ {
     if (err.message === TEMPORARY_ERROR) {
       throw err;
diff --git a/lib/manager/npm/post-update/yarn.spec.ts b/lib/manager/npm/post-update/yarn.spec.ts
index 05d494571a73803252753b395d7c06bb82e7313e..0a3ceceb76b688961a00c1f66cb4ea9ec524b55c 100644
--- a/lib/manager/npm/post-update/yarn.spec.ts
+++ b/lib/manager/npm/post-update/yarn.spec.ts
@@ -1,13 +1,13 @@
+import { exec as _exec } from 'child_process';
 import fs from 'fs-extra';
 import {
   ExecSnapshots,
   envMock,
-  exec,
   mockExecAll,
 } from '../../../../test/exec-util';
 import { Fixtures } from '../../../../test/fixtures';
-import { env } from '../../../../test/util';
-import { GlobalConfig } from '../../../config/global';
+import { mocked } from '../../../../test/util';
+import * as _env from '../../../util/exec/env';
 import * as yarnHelper from './yarn';
 
 jest.mock('fs-extra', () =>
@@ -17,6 +17,9 @@ jest.mock('child_process');
 jest.mock('../../../util/exec/env');
 jest.mock('./node-version');
 
+const exec: jest.Mock<typeof _exec> = _exec as any;
+const env = mocked(_env);
+
 delete process.env.NPM_CONFIG_CACHE;
 
 // TODO: figure out snapshot similarity for each CI platform (#9617)
@@ -32,7 +35,6 @@ describe('manager/npm/post-update/yarn', () => {
     jest.clearAllMocks();
     jest.resetModules();
     env.getChildProcessEnv.mockReturnValue(envMock.basic);
-    GlobalConfig.set({ localDir: '' });
   });
 
   it.each([
@@ -186,7 +188,6 @@ describe('manager/npm/post-update/yarn', () => {
   ])(
     'performs lock file maintenance using yarn v%s',
     async (yarnVersion, yarnCompatibility, expectedFsCalls) => {
-      GlobalConfig.set({ localDir: '.' });
       Fixtures.mock(
         {
           '.yarnrc': null,
diff --git a/lib/manager/npm/post-update/yarn.ts b/lib/manager/npm/post-update/yarn.ts
index 5f717ba7cee847e36de31e41b4ae311eed3d8688..5420e46b27963c4b2fe1280a26ba442d70c9b6ef 100644
--- a/lib/manager/npm/post-update/yarn.ts
+++ b/lib/manager/npm/post-update/yarn.ts
@@ -12,27 +12,19 @@ import { logger } from '../../../logger';
 import { ExternalHostError } from '../../../types/errors/external-host-error';
 import { exec } from '../../../util/exec';
 import type { ExecOptions } from '../../../util/exec/types';
-import {
-  deleteLocalFile,
-  exists,
-  readLocalFile,
-  writeLocalFile,
-} from '../../../util/fs';
+import { exists, readFile, remove, writeFile } from '../../../util/fs';
 import { newlineRegex, regEx } from '../../../util/regex';
 import type { PostUpdateConfig, Upgrade } from '../../types';
 import { getNodeConstraint } from './node-version';
 import type { GenerateLockFileResult } from './types';
 
 export async function checkYarnrc(
-  lockFileDir: string
+  cwd: string
 ): Promise<{ offlineMirror: boolean; yarnPath: string | null }> {
   let offlineMirror = false;
   let yarnPath: string = null;
   try {
-    const yarnrc = await readLocalFile(
-      upath.join(lockFileDir, '.yarnrc'),
-      'utf8'
-    );
+    const yarnrc = await readFile(`${cwd}/.yarnrc`, 'utf8');
     if (is.string(yarnrc)) {
       const mirrorLine = yarnrc
         .split(newlineRegex)
@@ -50,10 +42,7 @@ export async function checkYarnrc(
           regEx(/^yarn-path\s+"?.+?"?$/gm),
           ''
         );
-        await writeLocalFile(
-          upath.join(lockFileDir, '.yarnrc'),
-          scrubbedYarnrc
-        );
+        await writeFile(`${cwd}/.yarnrc`, scrubbedYarnrc);
         yarnPath = null;
       }
     }
@@ -74,12 +63,12 @@ export function isYarnUpdate(upgrade: Upgrade): boolean {
 }
 
 export async function generateLockFile(
-  lockFileDir: string,
+  cwd: string,
   env: NodeJS.ProcessEnv,
   config: PostUpdateConfig = {},
   upgrades: Upgrade[] = []
 ): Promise<GenerateLockFileResult> {
-  const lockFileName = upath.join(lockFileDir, 'yarn.lock');
+  const lockFileName = upath.join(cwd, 'yarn.lock');
   logger.debug(`Spawning yarn install to create ${lockFileName}`);
   let lockFile = null;
   try {
@@ -113,7 +102,7 @@ export async function generateLockFile(
     let cmdOptions = ''; // should have a leading space
     if (config.skipInstalls !== false) {
       if (isYarn1) {
-        const { offlineMirror, yarnPath } = await checkYarnrc(lockFileDir);
+        const { offlineMirror, yarnPath } = await checkYarnrc(cwd);
         if (!offlineMirror) {
           logger.debug('Updating yarn.lock only - skipping node_modules');
           // The following change causes Yarn 1.x to exit gracefully after updating the lock file but without installing node_modules
@@ -156,7 +145,7 @@ export async function generateLockFile(
     }
     const tagConstraint = await getNodeConstraint(config);
     const execOptions: ExecOptions = {
-      cwdFile: lockFileName,
+      cwd,
       extraEnv,
       docker: {
         image: 'node',
@@ -226,7 +215,7 @@ export async function generateLockFile(
         `Removing ${lockFileName} first due to lock file maintenance upgrade`
       );
       try {
-        await deleteLocalFile(lockFileName);
+        await remove(lockFileName);
       } catch (err) /* istanbul ignore next */ {
         logger.debug(
           { err, lockFileName },
@@ -239,10 +228,7 @@ export async function generateLockFile(
     await exec(commands, execOptions);
 
     // Read the result
-    lockFile = await readLocalFile(lockFileName, 'utf8');
-    if (lockFile === null) {
-      throw new Error('Error reading local file');
-    }
+    lockFile = await readFile(lockFileName, 'utf8');
   } catch (err) /* istanbul ignore next */ {
     if (err.message === TEMPORARY_ERROR) {
       throw err;