You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
test-lib: should be able to call inject AsyncTestCompleter within beforeEach but throws instead (alpha-36) #4035
Often useful to complete test setup in the beforeEach when the setup involves BOTH injection and an async invocation of a method on the injected service. Then subsequent tests can be synchronous.
Here's an example:
describe('#removeHero(hero)', () => {
let service: HeroService;
let cachedHeroes:Hero[];
// prime the HeroService's cache asynchronously
// notice we can use `injectAsync` in a `beforeEach` too!
beforeEach(
inject([AsyncTestCompleter, HeroService], (async: AsyncTestCompleter, hs:HeroService) => {
var done = async.done.bind(async); // convenience
service = hs;
service.getAllHeroes()
.then(heroes => cachedHeroes = heroes)
.catch(fail).then(done, done)
}));
// the following tests can be synchronous because the tested `remove` method is synchronous
// it presupposes that the cache of heroes has been filled by a previous `getAllHeroes` async call
...
});
Unfortunately, this throws:
Error: Error during instantiation of AsyncTestCompleter!.
Error: DI Exception
at InstantiationError.BaseException (http://localhost:8080/node_modules/angular2/bundles/angular2.dev.js:7767:25)
at InstantiationError.AbstractBindingError (http://localhost:8080/node_modules/angular2/bundles/angular2.dev.js:9117:66)
at new InstantiationError (http://localhost:8080/node_modules/angular2/bundles/angular2.dev.js:9159:64)
... more ...
Unfortunately, it is not possible to inject the AsyncTestCompleter in a beforeEach because it depends on done which is a parameter to it (and the likes).
However we should investigate why we don't get the expected & clearer error message.
I'm seeing the following boilerplate at the top of all my it tests ... and something similar at the top of tests throughout the Angular code base.
it('looking for something',
injectTcb((done, tcb) => { // injectTcb is my helper
tcb.overrideTemplate(SomeComponent, template)
.createAsync(SomeComponent)
.then((rootTC: RTC) => {
... at last we can do something interesting ...
})
.catch(fail).then(done, done);
}));
This is just nuts!
It should be closer to:
let rootTC:RootTestComponent;
beforeEach(injectTcb((done, tcb) => { // injectTcb is my helper
tcb.overrideTemplate(SomeComponent, template)
.createAsync(SomeComponent)
.then((rtc: RTC) => rootTC = rtc)
.catch(fail).then(done, done);
}));
it('looking for something synchronously', () => {
... test something ...
});
it('looking for something async', (done:DoneFn) => {
... test something async ...
.catch(fail).then(done, done);
});
You're actually right, done is actually a parameter to both beforeEach and it.
However jasmine's beforeEach is used by beforeEachBindings and the beforeEach used in the unit tests is actually a test_lib construct. I'm not sure if/how we can support injecting an AsyncTestCompleter there.
The AsyncTestCompleter is a PITA. It's an object with a done fn. Why does it exist? DART? I never use it. In fact, my first action is let done=async.done.bind(async);. My test helpers do this for me.
At worst a dedicated beforeEachSomething (akin to beforeEachBinding) could do the trick. Ideally I could combine test-binding set up and TCB initialization in the same beforeEach....
I would be happy to work w/ the person responsible for testing to come up with a more efficient API.
AsycTestCompleter is needed to inject? That is hard to fathom. I asked Igor about this thing too. He doesn't know why it exists either. We both suspect it's. A DART artifact that has no relevance to the JS developer.
All beside the point really. The more I look at the code the more I am convinced that this is relatively easy to fix. Might have a moment to try.
Meanwhile, I roll my own helper that creates a beforeEach like function that I then pass into the it as the test definition fn. Has the same effect as a beforeEach and DRYs out the test. I recommend this approach to others who stumble into this question.
changed the title [-]test-lib: should be able to call inject within `beforeEach` but throws instead (alpha-36)[/-][+]test-lib: should be able to call inject AsyncTestCompleter within `beforeEach` but throws instead (alpha-36)[/+]on Sep 28, 2015
It exists so that we have a type for injection. Otherwise how do you refer to the function
Example:
(done:Function) => ...; can not be injected. What is Function?
you could write (@Inject(AsyncTestCompleter) done:Function) => ... that would work but at that point you may as well just do (done:AsyncTestCompleter) => ...
My first reaction is "why are we using DI to supply this value to the callback?" I don't have to do that in any of my wrapper functions. I do say that the first argument past to the callback will be the done function as we see here: injectAsync([], done => { done()})
If I'm injecting something, well that looks like this: injectAsync([d1, d2], (done, d1, d2) => { done()})
This works great for me and I'm not sure what the objection would be.
But for the sake of argument, let's suppose you wanted to use DI to inject done and let the developer pick where it goes in the parameter list.
You absolutely can represent the Jasmine done in the manner most friendly to the test developer.
All of this is quite apart from the issue itself which asks _"Why can't I have the AsyncTestCompleter .. or better yet ... the done function ... from within the beforeEach?"_
Activity
vicb commentedon Sep 8, 2015
Unfortunately, it is not possible to inject the
AsyncTestCompleterin abeforeEachbecause it depends ondonewhich is a parameter toit(and the likes).However we should investigate why we don't get the expected & clearer error message.
wardbell commentedon Sep 8, 2015
Huh?
doneis passed into thebeforeEach. I write non-Angular asyncbeforeEachmethods all the time.wardbell commentedon Sep 8, 2015
I'm seeing the following boilerplate at the top of all my
ittests ... and something similar at the top of tests throughout the Angular code base.This is just nuts!
It should be closer to:
vicb commentedon Sep 8, 2015
You're actually right,
doneis actually a parameter to bothbeforeEachandit.However jasmine's
beforeEachis used bybeforeEachBindingsand thebeforeEachused in the unit tests is actually a test_lib construct. I'm not sure if/how we can support injecting anAsyncTestCompleterthere.wardbell commentedon Sep 8, 2015
The
AsyncTestCompleteris a PITA. It's an object with adonefn. Why does it exist? DART? I never use it. In fact, my first action islet done=async.done.bind(async);. My test helpers do this for me.wardbell commentedon Sep 8, 2015
At worst a dedicated
beforeEachSomething(akin tobeforeEachBinding) could do the trick. Ideally I could combine test-binding set up and TCB initialization in the samebeforeEach....I would be happy to work w/ the person responsible for testing to come up with a more efficient API.
vicb commentedon Sep 8, 2015
To be able to
inject()dependencies.wardbell commentedon Sep 9, 2015
AsycTestCompleteris needed to inject? That is hard to fathom. I asked Igor about this thing too. He doesn't know why it exists either. We both suspect it's. A DART artifact that has no relevance to the JS developer.All beside the point really. The more I look at the code the more I am convinced that this is relatively easy to fix. Might have a moment to try.
Meanwhile, I roll my own helper that creates a
beforeEachlike function that I then pass into theitas the test definition fn. Has the same effect as abeforeEachand DRYs out the test. I recommend this approach to others who stumble into this question.[-]test-lib: should be able to call inject within `beforeEach` but throws instead (alpha-36)[/-][+]test-lib: should be able to call inject AsyncTestCompleter within `beforeEach` but throws instead (alpha-36)[/+]mhevery commentedon Sep 28, 2015
It exists so that we have a type for injection. Otherwise how do you refer to the function
Example:
(done:Function) => ...;can not be injected. What isFunction?you could write
(@Inject(AsyncTestCompleter) done:Function) => ...that would work but at that point you may as well just do(done:AsyncTestCompleter) => ...wardbell commentedon Sep 29, 2015
My first reaction is "why are we using DI to supply this value to the callback?" I don't have to do that in any of my wrapper functions. I do say that the first argument past to the callback will be the
donefunction as we see here:injectAsync([], done => { done()})If I'm injecting something, well that looks like this:
injectAsync([d1, d2], (done, d1, d2) => { done()})This works great for me and I'm not sure what the objection would be.
But for the sake of argument, let's suppose you wanted to use DI to inject
doneand let the developer pick where it goes in the parameter list.You absolutely can represent the Jasmine
donein the manner most friendly to the test developer.Here is a plunker that demonstrates.
There is a trick; one must represent the
donefn as if it were a class:You will know better than I whether this actually has to be exported and revealed. I'll bet you can bury it.
Anyway, when you have the actual
donefunction in hand, you bind it into the list of testbindings that you're already building:And now it's available as a callable function wherever you inject it. In my plunker I injected it into a component's constructor but you get the idea:
All of this is quite apart from the issue itself which asks _"Why can't I have the
AsyncTestCompleter.. or better yet ... thedonefunction ... from within thebeforeEach?"_vicb commentedon Sep 29, 2015
would the TS compiler be happy with that ?
One reason to have a class is to make the Dart compiler happy. But actually you should be able to implement the
Functioninterface:Looking forward to your PR :)
5 remaining items
juliemr commentedon Oct 13, 2015
Done with a1fa2e4
angular-automatic-lock-bot commentedon Sep 7, 2019
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
This action has been performed automatically by a bot.