fix(appium): Return a non-zero exit code if an extension script execution fails (#21563)

This commit is contained in:
Mykola Mokhnach
2025-09-08 12:19:28 +02:00
committed by GitHub
parent 3f716cff52
commit 5d73a4fb49
6 changed files with 32 additions and 14 deletions

View File

@@ -53,9 +53,11 @@ export default class DriverCliCommand extends ExtensionCliCommand {
}
/**
* Run a script from a driver
*
* @param {DriverRunOptions} opts
* @return {Promise<import('./extension-command').RunOutput>}
* @throws {Error} if the script fails to run
*/
async run({driver, scriptName, extraArgs}) {
return await super._run({

View File

@@ -927,33 +927,33 @@ class ExtensionCliCommand {
this.log.ok(`${scriptName} successfully ran`.green);
return {output: output.getBuff()};
} catch (err) {
this.log.error(`Encountered an error when running '${scriptName}': ${err.message}`.red);
return {error: err.message, output: output.getBuff()};
const message = `Encountered an error when running '${scriptName}': ${err.message}`;
throw this._createFatalError(message);
}
}
try {
await new B((resolve, reject) => {
this._runUnbuffered(moduleRoot, scriptPath, extraArgs)
.on('error', (err) => {
.once('error', (err) => {
// generally this is of the "I can't find the script" variety.
// this is a developer bug: the extension is pointing to a script that is not where the
// developer said it would be (in `appium.scripts` of the extension's `package.json`)
reject(err);
})
.on('close', (code) => {
.once('close', (code) => {
if (code === 0) {
resolve();
} else {
reject(new Error(`Script "${scriptName}" exited with code ${code}`));
reject(new Error(`Script exited with code ${code}`));
}
});
});
this.log.ok(`${scriptName} successfully ran`.green);
return {};
} catch (err) {
this.log.error(`Encountered an error when running '${scriptName}': ${err.message}`.red);
return {error: err.message};
const message = `Encountered an error when running '${scriptName}': ${err.message}`;
throw this._createFatalError(message);
}
}
}
@@ -1079,7 +1079,6 @@ export {ExtensionCliCommand as ExtensionCommand};
* Return value of {@linkcode ExtensionCliCommand._run}
*
* @typedef RunOutput
* @property {string} [error] - error message if script ran unsuccessfully, otherwise undefined
* @property {string[]} [output] - script output if `bufferOutput` was `true` in {@linkcode RunOptions}
*/

View File

@@ -52,9 +52,11 @@ export default class PluginCliCommand extends ExtensionCliCommand {
}
/**
* Run a script from a plugin
*
* @param {PluginRunOptions} opts
* @returns {Promise<import('./extension-command').RunOutput>}
* @throws {Error} if the script fails to run
*/
async run({plugin, scriptName, extraArgs}) {
return await super._run({

View File

@@ -59,12 +59,29 @@ export class RingBuffer {
this.size = size;
this.buffer = [];
}
/**
* Get the current buffer contents
*
* @returns {any[]}
*/
getBuff() {
return this.buffer;
}
/**
* Remove the oldest item from the buffer
*
* @returns {void}
*/
dequeue() {
this.buffer.shift();
}
/**
* Add an item to the buffer
*
* @param {any} item
*/
enqueue(item) {
if (this.buffer.length >= this.size) {
this.dequeue();

View File

@@ -405,9 +405,8 @@ describe('Driver CLI', function () {
});
describe('when the script fails', function () {
it('should return an error', async function () {
const out = await runRun([driverName, 'fake-error']);
out.should.have.property('error');
it('should throw an error', async function () {
await expect(runRun([driverName, 'fake-error'])).to.be.rejectedWith(Error);
});
});

View File

@@ -46,10 +46,9 @@ describe('Plugin CLI', function () {
out.should.not.have.property('error');
});
it('should run a valid plugin, valid error prone script, and return error in json', async function () {
it('should run a valid plugin, valid error prone script, and throw error', async function () {
const pluginName = 'fake';
const out = await runRun([pluginName, 'fake-error', '--json']);
out.should.have.property('error');
await expect(runRun([pluginName, 'fake-error', '--json'])).to.be.rejectedWith(Error);
});
it('should take a valid plugin, invalid script, and throw an error', async function () {