Current behavior
When interrupting the Cypress process with SIGINT during the execution of a test the following error is displayed:
We stopped running your tests because a plugin crashed.
Your pluginsFile threw an error from: /home/tom/cypress-test/src/plugin.ts
Error [ERR_IPC_CHANNEL_CLOSED]: Channel closed
at new NodeError (node:internal/errors:370:5)
at ChildProcess.target.send (node:internal/child_process:724:16)
at Object.send (/home/tom/.cache/Cypress/9.5.3/Cypress/resources/app/packages/server/lib/plugins/util.js:32:25)
at EventEmitter.<anonymous> (/home/tom/.cache/Cypress/9.5.3/Cypress/resources/app/packages/server/lib/plugins/preprocessor.js:45:16)
at EventEmitter.emit (node:events:406:35)
at Object.removeFile (/home/tom/.cache/Cypress/9.5.3/Cypress/resources/app/packages/server/lib/plugins/preprocessor.js:119:17)
at Object.options.onBrowserClose (/home/tom/.cache/Cypress/9.5.3/Cypress/resources/app/packages/server/lib/open_project.js:135:40)
at EventEmitter.<anonymous> (/home/tom/.cache/Cypress/9.5.3/Cypress/resources/app/packages/server/lib/browsers/index.js:212:19)
at Object.onceWrapper (node:events:513:28)
at EventEmitter.emit (node:events:394:28)
at BrowserWindow.<anonymous> (/home/tom/.cache/Cypress/9.5.3/Cypress/resources/app/packages/server/lib/browsers/electron.js:431:25)
at Object.onceWrapper (node:events:514:26)
at BrowserWindow.emit (node:events:406:35)
Based on the text above the stack trace I would assume I made a mistake in my plugin.ts pluginsFile, however, that is actually empty. Without a custom pluginFile, the error will default to the 'standard' Cypress plugin file (plugin.js).
Desired behavior
I would expect that Cypress checks whether or not the file:preprocessor child process is still connected or not terminated before trying to send something on its IPC channel. If disconnected or terminated, Cypress should not try to send something to the child process.
In other words, I would expect that I do not get an error.
Test code to reproduce
package.json:
{
"name": "cypress-interrupt-test",
"version": "1.0.0",
"main": "index.ts",
"scripts": {
"start": "node --loader ts-node/esm index.ts"
},
"devDependencies": {
"cypress": "^9.5.3",
"ts-node": "^10.7.0",
"typescript": "^4.6.3"
}
}
index.ts:
import cypress from "cypress";
cypress.run({
config: {
baseUrl: "http://localhost:2000",
supportFile: "src/overwrite.ts",
pluginsFile: "src/plugin.ts",
integrationFolder: "cypress/integration",
testFiles: ["**/*.*"],
},
spec: null,
quiet: true,
});
src/overwrite.ts:
src/plugin.ts:
/**
* @type {Cypress.PluginConfig}
*/
module.exports = (on, config) => {}
cypress/integration/interrupt.spec.ts:
describe('an elaborate test', () => {
it('can wait', () => {
cy.wait(10000); // wait to allow us to interrupt the Cypress process
});
});
The SUT is just a simple web server with two pages, / containing a link to /page2.html
Execute npm start or node --loader ts-node/esm index.ts.
Cypress Version
9.5.3
Other
Tested on Ubuntu 20.04 and 21.10, with node versions v16.5.0, v17.4.0, and v17.9.0. Also tested with Cypress 9.5.0.
The following check is performed before trying to send something, however, it purely checks whether or not the process is killed. The process might already have been disconnected at this point (or even terminated).
|
if (aProcess.killed) { |
|
return |
|
} |
aProcess looks like this when it passes the if above:
{
...,
connected: false,
signalCode: 'SIGINT',
exitCode: null,
killed: false,
...,
}
To at least make sure that the process is not disconnected this additional check should be added:
diff --git a/packages/server/lib/plugins/util.js b/packages/server/lib/plugins/util.js
index 8d0e823847..b0b6e19076 100644
--- a/packages/server/lib/plugins/util.js
+++ b/packages/server/lib/plugins/util.js
@@ -25,7 +25,7 @@ module.exports = {
return {
send (event, ...args) {
- if (aProcess.killed) {
+ if (aProcess.killed || !aProcess.connected) {
return
}
You could go even further by checking the termination status through .exitCode, but I do not think that would be more helpful in this situation.
Current behavior
When interrupting the Cypress process with
SIGINTduring the execution of a test the following error is displayed:We stopped running your tests because a plugin crashed. Your pluginsFile threw an error from: /home/tom/cypress-test/src/plugin.ts Error [ERR_IPC_CHANNEL_CLOSED]: Channel closed at new NodeError (node:internal/errors:370:5) at ChildProcess.target.send (node:internal/child_process:724:16) at Object.send (/home/tom/.cache/Cypress/9.5.3/Cypress/resources/app/packages/server/lib/plugins/util.js:32:25) at EventEmitter.<anonymous> (/home/tom/.cache/Cypress/9.5.3/Cypress/resources/app/packages/server/lib/plugins/preprocessor.js:45:16) at EventEmitter.emit (node:events:406:35) at Object.removeFile (/home/tom/.cache/Cypress/9.5.3/Cypress/resources/app/packages/server/lib/plugins/preprocessor.js:119:17) at Object.options.onBrowserClose (/home/tom/.cache/Cypress/9.5.3/Cypress/resources/app/packages/server/lib/open_project.js:135:40) at EventEmitter.<anonymous> (/home/tom/.cache/Cypress/9.5.3/Cypress/resources/app/packages/server/lib/browsers/index.js:212:19) at Object.onceWrapper (node:events:513:28) at EventEmitter.emit (node:events:394:28) at BrowserWindow.<anonymous> (/home/tom/.cache/Cypress/9.5.3/Cypress/resources/app/packages/server/lib/browsers/electron.js:431:25) at Object.onceWrapper (node:events:514:26) at BrowserWindow.emit (node:events:406:35)Based on the text above the stack trace I would assume I made a mistake in my
plugin.tspluginsFile, however, that is actually empty. Without a custompluginFile, the error will default to the 'standard' Cypress plugin file (plugin.js).Desired behavior
I would expect that Cypress checks whether or not the
file:preprocessorchild process is still connected or not terminated before trying to send something on its IPC channel. If disconnected or terminated, Cypress should not try to send something to the child process.In other words, I would expect that I do not get an error.
Test code to reproduce
package.json:{ "name": "cypress-interrupt-test", "version": "1.0.0", "main": "index.ts", "scripts": { "start": "node --loader ts-node/esm index.ts" }, "devDependencies": { "cypress": "^9.5.3", "ts-node": "^10.7.0", "typescript": "^4.6.3" } }index.ts:src/overwrite.ts:// is emptysrc/plugin.ts:cypress/integration/interrupt.spec.ts:The SUT is just a simple web server with two pages,
/containing a link to/page2.htmlExecute
npm startornode --loader ts-node/esm index.ts.Cypress Version
9.5.3
Other
Tested on Ubuntu 20.04 and 21.10, with node versions v16.5.0, v17.4.0, and v17.9.0. Also tested with Cypress 9.5.0.
The following check is performed before trying to send something, however, it purely checks whether or not the process is killed. The process might already have been disconnected at this point (or even terminated).
cypress/packages/server/lib/plugins/util.js
Lines 28 to 30 in 933e0eb
aProcesslooks like this when it passes theifabove:To at least make sure that the process is not disconnected this additional check should be added:
You could go even further by checking the termination status through
.exitCode, but I do not think that would be more helpful in this situation.