]> git.ardis.lu - envpass/commitdiff
Refactor hardcoded `childProcess.execSync` into dependency injection
authorArdis Lu <ardisglu@gmail.com>
Tue, 8 Sep 2026 05:12:56 +0000 (22:12 -0700)
committerArdis Lu <ardisglu@gmail.com>
Tue, 8 Sep 2026 05:12:56 +0000 (22:12 -0700)
This change enables concurrent tests without inter-test thrashing on the `childProcess` mocks.

src/command.js
test/index.test.js

index adea1c9c5b887dcb84eb2d830768397845b6cdc5..3b571078f1799b3bfd3836042d93b78a1e500042 100644 (file)
@@ -103,13 +103,17 @@ export async function encrypt(options = {}) {
  * @property {GetPrfOptions} [getPrfOptions] Options for the passkey page and server.
  * @property {Logger} [logger] Logger to use to record diagnostic information. The default value is `{}` (i.e.,
  * drop all logs).
+ * @property {(command: string) => unknown} [exec] Function to call if there are additional arguments passed in the
+ * command after `decrypt`. The default value is
+ * {@link https://nodejs.org/api/child_process.html#child_processexecsynccommand-options|`childProcess.execSync`}
+ * with the option `{ stdio: 'inherit' }`.
  */
 
 /**
  * Decrypt an envpass encrypted .env file using a passkey.
  * @param {DecryptOptions} [options] Options to configure the decryption.
- * @param {{ args?: Array<string> }} [command] Excess arguments passed to the command, which will be executed as
- * a child process after decryption.
+ * @param {{ args?: Array<string> }} [command] Excess arguments passed to the command, which will be passed on
+ * to the `exec` function.
  * @returns {Promise<void>} `Promise` resolving when the decryption is complete.
  */
 export async function decrypt(options = {}, { args = [] } = {}) {
@@ -119,7 +123,8 @@ export async function decrypt(options = {}, { args = [] } = {}) {
     injectInProcess = false,
     notEncryptedValue = 'ignore',
     getPrfOptions = { port: undefined },
-    logger = {}
+    logger = {},
+    exec = command => childProcess.execSync(command, { stdio: 'inherit' })
   } = options;
 
   const env = /** @type {Record<string, string>} */ (
@@ -174,6 +179,6 @@ export async function decrypt(options = {}, { args = [] } = {}) {
   }
   if (args.length > 0) {
     logger.debug?.('Follow-on command found, executing in child process.');
-    childProcess.execSync(args.join(' '), { stdio: 'inherit' });
+    exec(args.join(' '));
   }
 }
\ No newline at end of file
index 79aeeae39b505a246fe1a6dcfbc1279cb76e0b85..92c66d60db158d8108aaa09ea62432a8fc9596d6 100644 (file)
@@ -165,19 +165,19 @@ suite('decrypt', () => {
     logger.assertCounts({ debug: 3, info: 0, warn: 0, error: 0 });
   });
   test('passes through excess args to execute', async (t) => {
-    const execMock = t.mock.method(childProcess, 'execSync', () => { });
     const envFile = await setupEnv(t, STD_ENV);
+    /** @type {(command: string) => void} */
+    const exec = command => deepStrictEqual(command, 'test test test');
 
-    await decrypt({ inFile: envFile }, { args: ['test', 'test', 'test'] });
-    deepStrictEqual(execMock.mock.calls.length, 1);
+    await decrypt({ inFile: envFile, exec }, { args: ['test', 'test', 'test'] });
   });
   test('passes through excess args to execute (with logs)', async (t) => {
-    const execMock = t.mock.method(childProcess, 'execSync', () => { });
     const envFile = await setupEnv(t, STD_ENV);
+    /** @type {(command: string) => void} */
+    const exec = command => deepStrictEqual(command, 'test test test');
     const logger = new MockLogger();
 
-    await decrypt({ inFile: envFile, logger }, { args: ['test', 'test', 'test'] });
-    deepStrictEqual(execMock.mock.calls.length, 1);
+    await decrypt({ inFile: envFile, exec, logger }, { args: ['test', 'test', 'test'] });
     logger.assertCounts({ debug: 4, info: 0, warn: 0, error: 0 });
   });
 });
This page took 0.038058 seconds and 4 git commands to generate.