diff --git a/detox/local-cli/startCommand/AppStartCommand.js b/detox/local-cli/startCommand/AppStartCommand.js index 8078e8d3b3..95ec835903 100644 --- a/detox/local-cli/startCommand/AppStartCommand.js +++ b/detox/local-cli/startCommand/AppStartCommand.js @@ -1,4 +1,5 @@ -const execa = require('execa'); +const tinyexec = require('tinyexec'); +const { tokenizeArgs } = require('args-tokenizer'); const detox = require('../../internals'); const { DetoxRuntimeError } = require('../../src/errors'); @@ -36,12 +37,15 @@ class AppStartCommand { } }; - this._cpHandle = execa.command(cmd, { - stdio: ['ignore', 'inherit', 'inherit'], - shell: true + const [command, ...args] = tokenizeArgs(cmd); + this._cpHandle = tinyexec.x(command, args, { + nodeOptions: { + stdio: ['ignore', 'inherit', 'inherit'], + shell: true + } }); - this._cpHandle.on('error', onError); - this._cpHandle.on('exit', (code, signal) => { + this._cpHandle.process.on('error', onError); + this._cpHandle.process.on('exit', (code, signal) => { const reason = code == null ? `signal ${signal}` : `code ${code}`; const msg = `Command exited with ${reason}: ${cmd}`; if (signal || code === 0) { diff --git a/detox/package.json b/detox/package.json index 4acef5c82a..1643aca0a6 100644 --- a/detox/package.json +++ b/detox/package.json @@ -91,11 +91,11 @@ "@wix-pilot/core": "^3.4.2", "@wix-pilot/detox": "^1.0.13", "ajv": "^8.6.3", + "args-tokenizer": "^0.3.0", "bunyan": "^1.8.12", "bunyan-debug-stream": "^3.1.0", "caf": "^15.0.1", "chalk": "^4.0.0", - "execa": "^5.1.1", "find-up": "^5.0.0", "fs-extra": "^11.0.0", "funpermaproxy": "^1.1.0", @@ -118,6 +118,7 @@ "stream-json": "^1.7.4", "strip-ansi": "^6.0.1", "telnet-client": "1.2.8", + "tinyexec": "^0.3.0", "tmp": "^0.2.1", "trace-event-lib": "^1.3.1", "which": "^1.3.1", diff --git a/detox/test/integration/bail-test.test.js b/detox/test/integration/bail-test.test.js index 5282f3f2e3..f5cb1779b2 100644 --- a/detox/test/integration/bail-test.test.js +++ b/detox/test/integration/bail-test.test.js @@ -1,22 +1,24 @@ -const _ = require('lodash'); -const execa = require('execa'); +const tinyexec = require('tinyexec'); +const { tokenizeArgs } = require('args-tokenizer'); describe('jest --bail tests', () => { test.each([ `detox test -c stub --config integration/e2e/config.js --bail --maxWorkers 2 --retries 1 flaky passing-simple`, - `cross-env DETOX_CONFIGURATION=stub jest --config integration/e2e/config.js --bail --runInBand passing-simple`, + `cross-env DETOX_CONFIGURATION=stub jest --config integration/e2e/config.js --bail --runInBand passing-simple` ])('should pass: %s', async (cmd) => { console.log(`Running: ${cmd}`); - const handle = execa.commandSync(cmd, { stdio: 'inherit', shell: true }); + const [command, ...args] = tokenizeArgs(cmd); + const handle = await tinyexec.x(command, args, { nodeOptions: { stdio: 'inherit', shell: true } }); expect(handle.exitCode).toBe(0); }); test.each([ `detox test -c stub --config integration/e2e/config.js --bail --runInBand --retries 0 flaky passing-simple`, - `cross-env DETOX_CONFIGURATION=stub jest --config integration/e2e/config.js --maxWorkers 4 flaky passing`, + `cross-env DETOX_CONFIGURATION=stub jest --config integration/e2e/config.js --maxWorkers 4 flaky passing` ])('should fail: %s', async (cmd) => { console.log(`Running: ${cmd}`); - const handle = _.attempt(() => execa.commandSync(cmd, { stdio: 'inherit', shell: true })); + const [command, ...args] = tokenizeArgs(cmd); + const handle = await tinyexec.x(command, args, { nodeOptions: { stdio: 'inherit', shell: true } }); expect(handle.exitCode).not.toBe(0); }); }); diff --git a/detox/test/integration/initialization-test.test.js b/detox/test/integration/initialization-test.test.js index 6a89574480..a35d86e88b 100644 --- a/detox/test/integration/initialization-test.test.js +++ b/detox/test/integration/initialization-test.test.js @@ -1,4 +1,5 @@ -const execa = require('execa'); +const tinyexec = require('tinyexec'); +const { tokenizeArgs } = require('args-tokenizer'); describe('Initialization (context) tests', () => { test.each([ @@ -8,9 +9,10 @@ describe('Initialization (context) tests', () => { `cross-env DETOX_CONFIGURATION=stub jest --config integration/e2e/config.js --runInBand passing-simple`, `detox test -c stub --config integration/e2e/config.js --maxWorkers 2 --retries 1 flaky passing-simple`, - `cross-env DETOX_CONFIGURATION=stub jest --config integration/e2e/config.js --maxWorkers 2 passing-simple`, + `cross-env DETOX_CONFIGURATION=stub jest --config integration/e2e/config.js --maxWorkers 2 passing-simple` ])('should run: %s', async (cmd) => { - const handle = execa.commandSync(cmd, { stdio: 'inherit', shell: true }); + const [command, ...args] = tokenizeArgs(cmd); + const handle = await tinyexec.x(command, args, { nodeOptions: { stdio: 'inherit', shell: true } }); expect(handle.exitCode).toBe(0); }); }); diff --git a/detox/test/package.json b/detox/test/package.json index 12f66d91b7..b637fd59d9 100644 --- a/detox/test/package.json +++ b/detox/test/package.json @@ -65,6 +65,7 @@ "@types/react": "^19.2.0", "@typescript-eslint/eslint-plugin": "^6.16.0", "@typescript-eslint/parser": "^6.16.0", + "args-tokenizer": "^0.3.0", "axios": "^1.7.7", "cross-env": "^7.0.3", "detox": "workspace:*", @@ -72,7 +73,6 @@ "eslint": "^8.56.0", "eslint-plugin-jest": "^28.11.0", "eslint-plugin-unicorn": "^50.0.1", - "execa": "^5.1.1", "express": "^4.15.3", "glob": "^7.2.0", "jest": "^30.0.3", @@ -81,6 +81,7 @@ "nyc": "^15.1.0", "p-iteration": "^1.1.8", "pngjs": "^3.4.0", + "tinyexec": "^0.3.0", "typescript": "^5.8.3" }, "jest-junit": { diff --git a/yarn.lock b/yarn.lock index 38e4ecf8a6..613e556861 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6462,6 +6462,13 @@ __metadata: languageName: node linkType: hard +"args-tokenizer@npm:^0.3.0": + version: 0.3.0 + resolution: "args-tokenizer@npm:0.3.0" + checksum: 10/b1335368758f9fc9b9bfc98ac4a5ea47b89be76fbc66c12bd2cb9e8460c9126e07ac3d251c1cf799df5bfde7b3d97559c55227c633ea82511bf969f69720bf39 + languageName: node + linkType: hard + "arr-diff@npm:^4.0.0": version: 4.0.0 resolution: "arr-diff@npm:4.0.0" @@ -10199,6 +10206,7 @@ __metadata: "@types/react": "npm:^19.2.0" "@typescript-eslint/eslint-plugin": "npm:^6.16.0" "@typescript-eslint/parser": "npm:^6.16.0" + args-tokenizer: "npm:^0.3.0" axios: "npm:^1.7.7" cross-env: "npm:^7.0.3" detox: "workspace:*" @@ -10206,7 +10214,6 @@ __metadata: eslint: "npm:^8.56.0" eslint-plugin-jest: "npm:^28.11.0" eslint-plugin-unicorn: "npm:^50.0.1" - execa: "npm:^5.1.1" express: "npm:^4.15.3" glob: "npm:^7.2.0" jest: "npm:^30.0.3" @@ -10222,6 +10229,7 @@ __metadata: react-native-permissions: "npm:^5.2.1" react-native-webview: "npm:^13.13.1" ssim.js: "npm:^3.5.0" + tinyexec: "npm:^0.3.0" typescript: "npm:^5.8.3" languageName: unknown linkType: soft @@ -10250,6 +10258,7 @@ __metadata: "@wix-pilot/core": "npm:^3.4.2" "@wix-pilot/detox": "npm:^1.0.13" ajv: "npm:^8.6.3" + args-tokenizer: "npm:^0.3.0" bunyan: "npm:^1.8.12" bunyan-debug-stream: "npm:^3.1.0" caf: "npm:^15.0.1" @@ -10261,7 +10270,6 @@ __metadata: eslint-plugin-no-only-tests: "npm:^3.1.0" eslint-plugin-node: "npm:^11.1.0" eslint-plugin-unicorn: "npm:^50.0.1" - execa: "npm:^5.1.1" find-up: "npm:^5.0.0" fs-extra: "npm:^11.0.0" funpermaproxy: "npm:^1.1.0" @@ -10290,6 +10298,7 @@ __metadata: stream-json: "npm:^1.7.4" strip-ansi: "npm:^6.0.1" telnet-client: "npm:1.2.8" + tinyexec: "npm:^0.3.0" tmp: "npm:^0.2.1" trace-event-lib: "npm:^1.3.1" typescript: "npm:^5.8.3" @@ -25840,6 +25849,13 @@ __metadata: languageName: node linkType: hard +"tinyexec@npm:^0.3.0": + version: 0.3.2 + resolution: "tinyexec@npm:0.3.2" + checksum: 10/b9d5fed3166fb1acd1e7f9a89afcd97ccbe18b9c1af0278e429455f6976d69271ba2d21797e7c36d57d6b05025e525d2882d88c2ab435b60d1ddf2fea361de57 + languageName: node + linkType: hard + "tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.15": version: 0.2.15 resolution: "tinyglobby@npm:0.2.15"