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

Support for asynchronous plugins #851

Closed
caitp opened this issue Dec 8, 2013 · 17 comments · Fixed by #3297 or karronoli/redpen#10 · May be fixed by Omrisnyk/npm-lockfiles#201
Closed

Support for asynchronous plugins #851

caitp opened this issue Dec 8, 2013 · 17 comments · Fixed by #3297 or karronoli/redpen#10 · May be fixed by Omrisnyk/npm-lockfiles#201

Comments

@caitp
Copy link

caitp commented Dec 8, 2013

Use case:

Looking to test an AngularJS module (angular-ui/ui-router) against several versions of AngularJS, with and without specific plugins (angular-animate).

So, rather than making a big ugly grunt task to manage all of this, I thought it would be nice to write a karma plugin to simplify this.

The goal is this: interface with the bower API to install modules before a test suite is run (by injecting config.bower into the framework factory)

The problem I run into is that I can't seem to find a way to have a plugin treated as asynchronous, so that it can wait for installation to complete.


This would be a super-awesome plugin (I think), and it would depend on a super-awesome feature of Karma.

I could look at implementing this, but I am not aware of all of the finer points of the karma-runner, so it would be really nice if someone could give this some consideration

@caitp
Copy link
Author

caitp commented Dec 8, 2013

Hmm, actually this might already be possible... it's really hard to tell, but I'll close this issue if it turns out to be already

...

So this doesn't appear to be doable just yet.

The simplest solution that I can think of is to modify node-di to await promise resolution before invoking functions. That's probably only a couple of lines to accomplish, but also leads to dependency on some promise implementation or another, which kind of sucks... I'll raise the issue over there though.

@vojtajina
Copy link
Contributor

Not sure I understand this correctly. You wanna a single test suite that
tests your project. You can tell Karma to test it with different versions
of Angular and Karma will run the suite multiple times, each time loading a
different version of angular. Is that about right?

On Sat, Dec 7, 2013 at 5:22 PM, Caitlin Potter [email protected]:

Hmm, actually this might already be possible... it's really hard to tell,
but I'll close this issue if it turns out to be already


Reply to this email directly or view it on GitHubhttps://github.com//issues/851#issuecomment-30072425
.

@caitp
Copy link
Author

caitp commented Dec 9, 2013

Yes, that's right...

So, I realize that this can be worked around with multiple karma configurations + external components checked into the tree, but my goal is to be able to do this from a plugin where it's easily reusable, and doesn't require components to be checked in.

The bar to this is, as stated, the Bower api is entirely asynchronous, and there seems to be no support for asynchronous injection in node-di/karma. I think there are probably other use cases for an asynchronous plugin mechanism as well, though.

The basic idea is to simply run the bower installation command during framework setup time, before the test suite actually begins


So like, I have a factory which injects config.bower, transforms a list of components into an array of endpoints for bower.commands.install()... Finally, capturing the error and end events would let the injector/karma know that the plugin's work is finished. (in the future, it might be nice to save components to specific subdirectories so that they wouldn't be re-downloaded each time the suite is run..)

The issue is that there's no way for the injector itself to support objects created asynchronously at this point, and currently no way (that I can tell) to tell Karma itself that the plugin is finished doing its work. Correcting the latter thing may be easier to do, however karma is a much more complicated piece of code than the injector itself, so I'm not quite sure where I'd begin to try and do that.

I was just thinking this might be worth looking at, plugins might in some cases need to perform some asynchronous work

@vojtajina
Copy link
Contributor

Well the plugin instantiation can be synchronous. It just needs to delay
the execution, which is doable.

You can hack the global emitter to override "file_list_modified" event. It
gets a promise with all the resolved files, so you need to wrap this
promise and delay it until all the stuff is installed.

Try to hack this then we can change Karma to make this possible without
hacks... How about that?

On Sun, Dec 8, 2013 at 4:43 PM, Caitlin Potter [email protected]:

Yes, that's right...

So, I realize that this can be worked around with multiple karma
configurations + external components checked into the tree, but my goal is
to be able to do this from a plugin where it's easily reusable, and doesn't
require components to be checked in.

The bar to this is, as stated, the Bower api is entirely asynchronous, and
there seems to be no support for asynchronous injection in node-di/karma. I
think there are probably other use cases for an asynchronous plugin
mechanism as well, though.


Reply to this email directly or view it on GitHubhttps://github.com//issues/851#issuecomment-30098187
.

@caitp
Copy link
Author

caitp commented Dec 11, 2013

That sounds like a good plan, I'll see how that works --- But what if multiple plugins wanted to do that? Seems like it would become problematic in that case

@vojtajina
Copy link
Contributor

Yeah, it's pretty nasty, but I think it should work...

On Tue, Dec 10, 2013 at 7:01 PM, Caitlin Potter [email protected]:

That sounds like a good plan, I'll see how that works --- But what if
multiple plugins wanted to do that? Seems like it would become problematic
in that case


Reply to this email directly or view it on GitHubhttps://github.com//issues/851#issuecomment-30290181
.

@caitp
Copy link
Author

caitp commented Apr 28, 2014

Re: vojtajina/node-di#8 (comment) --- @vojtajina if you want to assign this to me I can try to work on it this week, seems like a good thing to have

@vojtajina
Copy link
Contributor

So would async framework init (in Karma) be sufficient for your use case? In that case, the change is simple - you even don't need to change node-di, just change Karma to wait for all frameworks to finish.

@caitp
Copy link
Author

caitp commented May 1, 2014

Yeah, I think it should be good enough, so long as different frameworks never need to depend on each other

@caitp
Copy link
Author

caitp commented May 1, 2014

Ignore previous (deleted) comment, I just realized installing q didn't actually add a new package!

caitp added a commit to caitp/karma that referenced this issue May 1, 2014
… server

The API is to simply return a promise from a factory function, or use a promise as a value. The server
will wait for the collection of frameworks to resolve before carrying on starting the server.

This is useful for when setup requires some asynchronous startup.

Currently, any Promise api which is interoperable with q may be used.

In addition to this feature, this CL also adds a set of callbacks to the server, via an object for the
3rd parameter. This is useful for test purposes, and enables the test case to run faster, by not waiting
for the server to shut down via the second parameter.

Closes karma-runner#851
caitp added a commit to caitp/karma that referenced this issue May 1, 2014
… server

The API is to simply return a promise from a factory function, or use a promise as a value. The server
will wait for the collection of frameworks to resolve before carrying on starting the server.

This is useful for when setup requires some asynchronous startup.

Currently, any Promise api which is interoperable with q may be used.

In addition to this feature, this CL also adds a set of callbacks to the server, via an object for the
3rd parameter. This is useful for test purposes, and enables the test case to run faster, by not waiting
for the server to shut down via the second parameter.

Closes karma-runner#851
caitp added a commit to caitp/karma that referenced this issue May 1, 2014
… server

The API is to simply return a promise from a factory function, or use a promise as a value. The server
will wait for the collection of frameworks to resolve before carrying on starting the server.

This is useful for when setup requires some asynchronous startup.

Currently, any Promise api which is interoperable with q may be used.

In addition to this feature, this CL also adds a set of callbacks to the server, via an object for the
3rd parameter. This is useful for test purposes, and enables the test case to run faster, by not waiting
for the server to shut down via the second parameter.

Closes karma-runner#851
caitp added a commit to caitp/karma that referenced this issue May 3, 2014
… server

The API is to simply return a promise from a factory function, or use a promise as a value. The server
will wait for the collection of frameworks to resolve before carrying on starting the server.

This is useful for when setup requires some asynchronous startup.

Currently, any Promise api which is interoperable with q may be used.

In addition to this feature, this CL also adds a set of callbacks to the server, via an object for the
3rd parameter. This is useful for test purposes, and enables the test case to run faster, by not waiting
for the server to shut down via the second parameter.

Closes karma-runner#851
@marcins
Copy link

marcins commented Jun 23, 2014

FYI - I had a similar requirement - I wanted to do some action with the list of resolved files and have the result of that action available to the test code, so needed to be able to hold off initialising my framework until the file list was ready.

I followed @vojtajina's suggestion to hack the emitter - it's pretty nasty, but it works for my purposes.

Here's the rough pattern I used in my plugin factory function - the placeholder here is just a 5s timeout to demonstrate that it's working:

var originalEmit = emitter.emit;
emitter.emit = function (event, arg) {
    if (event === 'file_list_modified') {
        var originalPromise = arg;
        var defer = q.defer();
        originalPromise.then(function (files) {
            setTimeout(function () {
                defer.resolve(files);
            }, 5000);
        });
        originalEmit.call(emitter, event, defer.promise);
    } else {
        originalEmit.apply(emitter, arguments);
    }
};

@dignifiedquire
Copy link
Member

Just a warning, this hack won't work in 0.13 any more as the file_list_modified event does not emit a promise anymore.

I'm closing this issue for now as there hasn't been much activity lately.

@wilsonjackson
Copy link

@dignifiedquire I haven't had a chance to look yet — do you know if Karma has introduced any kind of real support for asynchronous plugins yet? If not, any plugin using this trick will probably be SOL until they remedy that.

@dignifiedquire
Copy link
Member

No we haven't yet. I'll reopen this, as it seems there is a need for supporting this properly.

@z-vr
Copy link

z-vr commented Jun 26, 2017

It would be really good to support this feature please. I want to write a framework which would start a certain server, but I don't have a way of making Karma wait before it is initialised. I could register it as pre-processor I suppose, but that's quite hackish.

@mboudreau
Copy link

Is this even possible yet? I tied returning a promise in the factory function, but it doesn't seem to wait for it to resolve before moving onto tests. This is extremely annoying to say the least.

@mjd0
Copy link

mjd0 commented Nov 7, 2017

git clone [email protected]:material-foundation/material-remixer-remote-web.git
cd material-remixer-remote-web && npm install

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment