Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interrupted file:preprocessor child process with disconnected IPC channel during preprocessor:close causes unclear plugin error #21010

Closed
tomudding opened this issue Apr 9, 2022 · 2 comments · Fixed by #21011

Comments

@tomudding
Copy link
Contributor

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:

// is empty

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.

@cypress-bot cypress-bot bot added the stage: needs review The PR code is done & tested, needs review label Apr 9, 2022
@cypress-bot cypress-bot bot added stage: pending release and removed stage: needs review The PR code is done & tested, needs review labels Apr 13, 2022
@cypress-bot
Copy link
Contributor

cypress-bot bot commented Apr 13, 2022

The code for this is done in cypress-io/cypress#21011, but has yet to be released.
We'll update this issue and reference the changelog when it's released.

@cypress-bot
Copy link
Contributor

cypress-bot bot commented Apr 25, 2022

Released in 9.6.0.

This comment thread has been locked. If you are still experiencing this issue after upgrading to
Cypress v9.6.0, please open a new issue.

@cypress-bot cypress-bot bot locked as resolved and limited conversation to collaborators Apr 25, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant