cypress-io/cypress

PluginEvents do not support multiple handlers

jeremygiberson opened this issue ยท 12 comments

Current behavior

Seemingly, as of cypress 10, if you have multiple plugins that register handlers for before:run, after:run, before:spec, or after:spec, only the last registered handler is dispatched.

Desired behavior

All event handlers should be dispatched.

Test code to reproduce

I've added a test spec for the scenario in the fork/branch: https://github.com/jeremygiberson/cypress/tree/run-events-multiple-bug. See pull request #22429

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  // setupNodeEvents can be defined in either
  // the e2e or component configuration
  e2e: {
    setupNodeEvents(on, config) {
      on('before:run', ()=>{ console.log('before:run first handler') });
      on('before:run', ()=>{ console.log('before:run second handler') });
    }
  }
})

On execution of cypress test, you will only see the presence of "before:run second handler" in the output.

Cypress Version

^10.0.0

Other

Based on cursory investigation it seems like this is due to the EventRegistrar implementation. It seems like this is the class that handles plugin event registration.

But the implementation is such that there can only be a single callback for an event.

export class EventRegistrar {
  private _registeredEvents: Record<string, Function> = {}
}

Presumably, the implementation should be such that multiple callbacks can be registered per event.

export class EventRegistrar {
  private _registeredEvents: Record<string, Array<Function>> = {}
}

I'm not familiar with the cypress internals, so take with a grain of salt.

@jeremygiberson thank you very much for the report and the PR reproducing the issue. It is very much appreciated! I gave your branch a pull and verified your findings.

I will leave your PR open until this issue is prioritized so that we can ensure the work you did for us gets included. I am going to mark it as a draft, though, so it doesn't get merged prematurely.

Is there a chance this'll be patched for v10?

@nagash77 any update on this?

Would love an update on this

Any news on this?

@matys84pl This is not currently slated for development in the near future. We of course always welcome contributions from the community if anyone were so inclined.

Hi all,
I've faced the same issue. So, I decided to create a library that can fix the problem. You just need to install the library with the following command:

npm i -D cypress-plugin-init 

And then, you need to import the initPlugins function and use it in your cypress.config.ts file:

// import the function
import { initPlugins } from 'cypress-plugin-init';

// For example you have two plugins:
const plugin1 = (on: Cypress.PluginEvents) => {
  on('before:run', (_) => console.log('[Plugin #1] Running before:run'));
};

const plugin2 = (on: Cypress.PluginEvents) => {
  on('before:run', (_) => console.log('[Plugin #2] Running before:run'));
};


export default defineConfig({
  e2e: {
   // ...
    setupNodeEvents(on, config) {
      // invoke the function with all plugins that you need instead of the 'plugin1' and 'plugin2'
      initPlugins(on, [plugin1, plugin2]);
    },
   // ...
  },
});

It will print the following output:

(Run Starting)
...
[Plugin #1] Running before:run
[Plugin #2] Running before:run
...
(Run Finished)

I too created a plugin to proxy events to multiple listeners cypress-on-fix

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  e2e: {
    // baseUrl, etc
    supportFile: false,
    fixturesFolder: false,
    setupNodeEvents(cypressOn, config) {
      const on = require('cypress-on-fix')(cypressOn)
      // use "on" to register plugins, for example
      // https://github.com/bahmutov/cypress-split
      require('cypress-split')(on, config)
      // https://github.com/bahmutov/cypress-watch-and-reload
      require('cypress-watch-and-reload/plugins')(on, config)
      // https://github.com/bahmutov/cypress-code-coverage
      require('@bahmutov/cypress-code-coverage/plugin')(on, config)
    },
  },
})
Deop commented

Hi @bahmutov I was trying to set this up but couldn't get it working. I'm still using plugin/index.js file which I then import into config file as setupNodeEvents, could you please give an example for this scenario?

@Deop can you open an issue in the https://github.com/kouzoh/test-framework-cypress/pull/2784 repo with a reproducible / code example?

Hi @elaichenkov I was trying to use your library but I get this warning
image
Can you please help what's happening here?

Closing as a duplicate of #5240