Plugin system for extending cucumber-js #2091
Replies: 8 comments 5 replies
-
I like the idea, and I agree with your analysis and choices 👌 |
Beta Was this translation helpful? Give feedback.
-
I think an approach where we try to identify and refactor existing/internal code towards using an API boundary that we could stabilise and make public sounds great. Happy to pair with you on this @davidjgoss if you want to bounce some ideas around. Not necessarily solving the same problem but worth adding for context: When @tooky and I re-wrote the guts of cucumber-ruby, we ended up with a "plugin" mechanism based on the chain-of-responsibility design pattern. Express's request handlers are another example of the same pattern. Each plugin (or "filter" as we called them) receives the stream of test cases (like a pickle, but with extra info about how to invoke it) and is given a receiver (the next filter in the chain) to whom it should pass on whichever test cases it chooses. It can filter out test cases by choosing not to pass them on, and it can also enrich or otherwise mutate test cases before passing them on. A lot of code fell into place when we adopted this model, allowing us to assemble most of Cucumber's behavour from lots of small pieces, e.g:
I'm not sure if you already have something like this inside cucumber-js, but it might be worth thinking about as part of this. I'm pretty sure it would provide what the TCP extension needs, for example. |
Beta Was this translation helpful? Give feedback.
-
https://github.com/cucumber/cucumber-electron is another piece worth considering in all this, currently implemented as a wrapper but we agreed (in theory) that it should really be part of this codebase. |
Beta Was this translation helpful? Give feedback.
-
More prior art is the https://github.com/cucumber/cucumber-ruby-wire/blob/main/lib/cucumber/wire.rb extension for cucumber-ruby which does use an officially-supported (though poorly documented / publicised) plugin API. |
Beta Was this translation helpful? Give feedback.
-
Formatters could also be a special form of a plugin. Maybe have someway for the plugin to declare its a formatter and thus to get passed a function to log (which will be either a file stream or stdout) In general, like the idea. Very curious what exactly will be the scope of what get supported |
Beta Was this translation helpful? Give feedback.
-
I just raised a PR that refactors the publish functionality to be a plugin (only an internal concept for now). So far this is just a plugin that passively listens for messages and does stuff outside of Cucumber off the back of that, but it's a good draft to drive some more discussion. |
Beta Was this translation helpful? Give feedback.
-
As I start to experiment with other use cases for this, it occurs to me that a plugin, much like a formatter, can only really operate at the "coordinator" level, since test execution often happens in a worker process (via the parallel runtime). This is kind of similar to Cypress, where a plugin operates within the Node.js process, and anything you want to happen in the browser is done via support code. I don't think this is a problem per se, or that we should change direction. I think most of the interesting plugin use cases are coordinator-level. But I think long term we'll want to come up with a nice solution for:
|
Beta Was this translation helpful? Give feedback.
-
I've started tagging issues with |
Beta Was this translation helpful? Give feedback.
-
🤔 What's the problem you're trying to solve?
If you want to augment the core functionality of Cucumber - for something that's not a formatter - you have two choices:
Neither of these options are great for the average user with a good idea, and both of these specific use cases would be better served by an official plugin mechanism so you can hook into Cucumber's test run lifecycle, change things, and react to things.
✨ What's your proposed solution?
TBA!
At a basic level we need two things:
A way to write a plugin
The bare minimum might be something like:
We'll also likely need:
stderr
(e.g. the publish banner)async inferOrder(pickles: Pickle[]): Promise<Pickle[]>
A way to reference a plugin
Something like:
I think a good start would be to create some plumbing for plugins internally, and reimplement the publish functionality in terms of that. I'm happy to give that a go.
Beta Was this translation helpful? Give feedback.
All reactions