-
-
Notifications
You must be signed in to change notification settings - Fork 408
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
Registry / Container reform #46
Conversation
`isolatedContainer` for unit testing. A mechanism will be developed to specify | ||
which initializers should be engaged in the initialization of this instance. | ||
In this way, we can avoid duplication of registration logic, as is currently | ||
done in a most un-DRY manner in the [isolatedContainer](https://github.com/switchfly/ember-test-helpers/blob/master/lib/ember-test-helpers/isolated-container.js#L56-L79). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For Ember-Data we use DS._setupContainer
:
If Ember only needs to register/inject, then I would prefer such a hook since they can be easily layered onto a single registry in an arbitrary order.
However I note that you suggest the name be isolatedApplicationInstance
- does this imply you will return a real instance and not simply a container with a configured registry?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. If Container
is private and only accessible through an ApplicationInstance
, then I believe that's the level at which it should be available for testing.
With the recent container / registry split we were burned pretty badly with our test helpers. We had created quite a few helpers to do proper testing setup/mocking/teardown/etc. I personally am a little weary of the idea of isolating these given that interaction with the container had previously been encouraged for testing and other initializers. I guess I have no real concrete reason as to this shouldn't be done, other than I don't really want to refactor all my test helpers again. |
Big, big 👍. I think this proposal kills several 🐦s with one stone:
I can't speak for everyone, of course, but @wycats and I have been very openly against anyone treating the container API as public. There are cases where you have to use it, but there is a reason it is marked private. This proposal allows us to (finally) provide an API we can encourage people to use. |
@tomdale Certainly my primary use case is around testing. Using containers to initialize and mock stuff. But also, it is one of the arguments provided when creating an initializer. And for a period of time, before services people were encourage to used injection this way. This is one of dozens examples that come up when you Google ember dependency injection. http://ember.zone/ember-application-initializers/ Any ways, just to make my position clear, I'm not against it. Just pointing out it might be a source of pain for some folks. |
@workmanw Point taken. With Dan's RFC, assuming you were indeed sticking to initializers and coloring within the lines, the refactor is extremely mechanical: just update all of your initializers and replace |
|
Seems reasonable. Perhaps |
@tomdale Thanks for your support of this proposal. @workmanw I'm sorry that the churn in this area has already affected you. I initiated much of this churn with the Registry / Container split as part of the SSR refactor. That was a necessary precondition to the Application / ApplicationInstance split that @tomdale and @wycats performed to enable SSR. Only now that their work is nearing completion is it possible to come back to rethink Registry and Container access. I hope the end result of all this work is a clean set of interfaces that shield developers from any complexity introduced by these refactors. And since these interfaces will finally be thoroughly public, we can avoid similar churn and breakage in the future. |
|
||
# Alternatives | ||
|
||
The obvious alternative is to make `Container` and `Registry` fully public |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
most of the in-app usages of container are the result of not having:
- class level injection rules (not global injection rules, which don't inherit)
- factory injections are backwards, instances should get references to factories and not the other way around.
beyond that, there exist dynamic situations where has/lookupFactory
should be exposed, but lookup
should never be exposed as this should have been the result of an injection (lazy or constructor).
I'm not sure if this is something that fits the scope of this RFC, if that's the case just ignore me. Lately I've been digging into testing story for Ember.js and one thing bothers me about testing an application with services. At the moment there's no easy way to inject mocked services during acceptance testing, or at least there's no way that I know of. It would be great if new public API allowed something like this:
This would make acceptance tests use a mocked service. There are multiple ways to handle such behaviour, but all that I know of require preparing code for substitution (like creating adapters in ember-data). |
Ideally we will have a way to register a replacement service as described above, using a public API. In testing comma components this has proven very necessary to isolate issues in the front end vs. the back end code. |
That was comms components. |
@drogus I am also very interested in the acceptance testing story. I think there are at least three blocking issues:
|
Yeah, the only workaround I found to overcome this issues is to reopen resolver: application.registry.resolver.__resolver__.reopen({
resolve: function(fullName) {
if(fullName === 'service:storage') {
return mockService;
} else {
return this._super.apply(this, arguments);
}
}
}); which is clearly not very elegant and will break with any bigger internal changes. |
Here's one way to solve the acceptance testing story:
In this way, registrations will be resolved in order by:
In this way, mocks can be registered with the application instance and those registrations will take precedent when resolved. |
internally maintained container: | ||
|
||
* `lookup` | ||
* `lookupFactory` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, so code such as in ember-islands that finds App.DocPrinterComponent
would change as below?
-var container = App.__container__;
-var componentLookup = container.lookup('component-lookup:main');
-var component = componentLookup.lookupFactory('doc-printer', container);
+var component = App.lookupFactory('doc-printer');
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or would it be like
App.instanceInitializer({
initialize: function(instance) {
instance.container.lookupFactory('doc-printer');
}
});
(h/t al3xnull in slack https://embercommunity.slack.com/archives/needhelp/p1434479693008755 )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry to miss your earlier question. So the lookup
and lookupFactory
methods would be exposed directly on the instance, in the same way as register
and inject
:
App.instanceInitializer({
initialize: function(instance) {
instance.lookupFactory('doc-printer');
}
});
(Note: @stefanpenner has concerns about lookupFactory
as it's currently implemented. It may be replaced entirely for 2.0)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
alrighty, thanks
@dgeb that means that there is parallel |
@igorT there is no (non-deprecated) There are two registries now: one on the application instance and one on the application. Each has a When resolving, the instance's registry "falls back" to the application's registry if it can't resolve. If a resolver is associated with either registry, then it will be consulted before the custom registrations in that registry. The solution here (which I'm about to PR) is to skip setting the resolver on the instance's registry and only set it on the application's registry. This allows custom registrations made through the instance's registry to take precedence over both the resolver and registrations made on the application's registry. |
My bad I misread |
Implemented and merged via emberjs/ember.js#11440 Should this RFC just be closed now? |
Yes :-) The filename should be changed to |
Thanks @mixonic! It's ready for review now. |
RFC