-
-
Notifications
You must be signed in to change notification settings - Fork 3k
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
🗣️ Discussion: Plugin notes #4116
Comments
cc @papandreou and @sunesimonsen who I discussed this sort of thing with |
Thanks for writing this down! First thing that popped up in my head: Would it work roughly the same way in the browser? I assume you(/plugins) could interact with the |
@papandreou You can interact with the Now that I wrote that, I'm somewhat less hesitant to introduce a |
a |
These are very good notes. Cross-linking them with #1457 and closing this issue to keep our queue small. |
I've done some thinking about the plugin system (or lack thereof) recently, as I was exploring adding native support for snapshot tests.
(I'm not sure adding native support for snapshot tests is a great idea, because e.g. snap-shot-it already exists and works fine; this is not the right issue in which to discuss it)
Here's a breakdown of the way things currently work:
--require
before the mainMocha
object is instantiated with any user-supplied options (and loads any test files)require('mocha').reporters
orrequire('mocha').interfaces
, e.g.,my-reporter
ormy-interface
, the custom reporter or interface implementation will be able to be referenced by--reporter my-reporter
or--ui my-interface
, respectively (because "registration" comes before instantiation ofMocha
)--file
will allow the user to be explicit about this; anything else will not make guarantees. Thus, a plugin loaded with--file
will have access to the root suite,describe
,it
, hooks, etc. Not every file "run" by Mocha needs to be a "test" file. If a global setup/teardown needs to happen, use--file <./path/to/harness.js>
; if it's a 3rd-party package,--file <packagename>
works identically.Some shortcomings of this (there are many, but here are a few), in order of (IMO) "least problematic" to "most problematic":
--file <packagename>
is rather unintuitive and cumbersome; it's not really designed for arbitrary plugins that need to operate at the root-suite level, but it works.--require
'd files which are not reporters nor interfaces cannot access any settings or options short of monkeypatchingrequire('mocha').prototype
.--file
or otherwise viarequire()
cannot access individual suites, hooks, nor test objects; all they can do is work with what Mocha injects into theglobal
context, the same as test files (describe()
,it()
, etc.). They cannot access theMocha
instance, nor theRunner
instance, nor reporters, etc.Some ways in which we can solve these issues:
Required Module Execution
Expand
--require
to look at the "return type" of a module. If it has a return type matching "a Mocha plugin", then save a reference to it, instantiate Mocha, and pass this Mocha instance to each module we've saved a reference to.What this would allow plugins to do (keep in mind this would be before mocha begins even loading files):
mocha.suite
Drawbacks of this approach:
delay
option programmatically and prepend a file into the list which executes Mocha'sglobal.run()
. Otherwise, there may be many breaking changes necessary to support "async listeners". On the plus side, it'd probably give us async suites "for free!"Probably best to define a more explicit plugin API surface where something loaded via
--require
would return some metadata and handler(s); maybe auto-loading of plugins could be a thing too. This would ideally provide a more "official" interface for defining custom interfaces and reporters, as well. That's... more work.Expose Events via Singleton
Given:
a.spec.js
which containsrequire('mocha-plugin')
mocha-plugin
which has a main module that containsconst Mocha = require('mocha')
(Mocha
is the main class found inlib/mocha.js
)We could expose
Mocha.events
(or whatever), which is a singleton EE that listens on events emitted from Mocha'sRunner
instance, and re-emits them with two parameters: the currentMocha
instance and whatever else the original event emits. For example:This suffers from the same problem as before, where these listeners must be synchronous. Again, a "proper" API surface would be better, so we can avoid exposing more internals. The
mocha
instance is passed along because while we can reasonably be sure that we only have onemocha
instance, we cannot always guarantee it.It would also be a good idea to allow packages loaded with
--require
to listen to these events. We don't even have aRunner
instance at this point, so we'd need to do something to work around that.It'd be ideal to allow plugins to function at both "setup time" and "run time", and have a similar API for each. The latter would necessarily have some restrictions on what it can do.
I don't think EE's are the right solution, as much of a time-saver they might be.
This will be very helpful to tooling authors trying to extend Mocha. But whatever we do, we're stuck with it.
cc @mochajs/core
The text was updated successfully, but these errors were encountered: