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

Injecting Angular 2 services into Angular 1's $controller #8757

Closed
SonofNun15 opened this issue May 20, 2016 · 8 comments
Closed

Injecting Angular 2 services into Angular 1's $controller #8757

SonofNun15 opened this issue May 20, 2016 · 8 comments

Comments

@SonofNun15
Copy link

@SonofNun15 SonofNun15 commented May 20, 2016

Related issue: #6655

Per this related issue, in Angular 1 components the Angular 2 injector is resolved via require and walking the DOM tree.

We unit test all of our Angular 1 controllers completely separate from the DOM for simplicity. We build them using $controller, passing in the necessary bindings. Then we trigger interactions on the controller and assert the results.

Our tests for controllers that inject downgraded Angular 2 components are all failing with Error: [$injector:unpr] Unknown provider: ng2.InjectorProvider <- ng2.Injector <- rlObjectService

After reading the related issue, it appears that this is caused because ngUpgrade can't find the Angular 2 injector by walking the DOM tree because there IS no DOM tree.

Is it possible to still test controllers in isolation like this when ngUpgrade is in play?

I assume we will still need to call bootstrap on the document before running tests?

@SonofNun15 SonofNun15 changed the title Injecting Angular 2 services into $controller Injecting Angular 2 services into Angular 1's $controller May 20, 2016
@SonofNun15
Copy link
Author

@SonofNun15 SonofNun15 commented May 20, 2016

To start with, we weren't actually calling bootstrap on the upgrade adapter, which looks necessary. Trying that now.

@yjaaidi
Copy link
Contributor

@yjaaidi yjaaidi commented May 21, 2016

Hi!

Interesting issue. Actually, you should not use angular mocks' module and inject but the upgradeProvider.

It's not documented yet but there are some clues in angular 2's source code.

1 - Your UpgradeAdapter instance should be a singleton.
2 - You should add your providers to the UpgradeAdapter singleton using UpgradeAdapter.addProvider.
3 - You should start the app using UpgradeAdapter.bootstrap then grab the UpgradeAdapterRef instance given to ready's callback function.
4 - Get the ng1Injector attribute from the UpgradeAdapterRef instance.
5 - Instantiate your service using the injector's synchronuous get method.

Here's a plunker with the solution:
https://embed.plnkr.co/EauYut/

We also published a blog post about angular 2 migration on Wishtack. We will soon be filling the blog with more posts about angular 2 testing.

http://www.blog.wishtack.com/#!AngularJS-vs-Angular-2-Should-I-Stay-or-Should-I-Go/cuhk/573b59710cf233ef713771b2

@SonofNun15
Copy link
Author

@SonofNun15 SonofNun15 commented May 21, 2016

We'll try this out this week.

@SonofNun15
Copy link
Author

@SonofNun15 SonofNun15 commented May 27, 2016

So you are telling me that we can't use $controller when ngUpgrade is in place? Started to implement this solution, but we are calling $controller in hundreds of tests, so changing every test is going to be really hard. Can't we just take the upgradeRef.ng2Injector and give it to the provider somehow since the original error was Unknown provider: ng2.InjectorProvider <- ng2.Injector <- rlObjectService?

@SonofNun15
Copy link
Author

@SonofNun15 SonofNun15 commented May 27, 2016

We tried doing this:

angular.module(testModule, [moduleName])
    .provider('ng2.Injector', function (): angular.IServiceProvider {
        return {
            $get: (): Injector => ng2Injector,
        };
    });

Didn't appear to help at all.

@SonofNun15
Copy link
Author

@SonofNun15 SonofNun15 commented May 27, 2016

ng2Injector was a closure that we set to upgradeRef.ng2Injector in upgradeAdapter.ready()

@SonofNun15
Copy link
Author

@SonofNun15 SonofNun15 commented May 27, 2016

We seem to have gotten by this problem. First, we had to use:

beforeEach(() => {
    angular.mock.module(moduleName)
});

To instantiate the module that is being bootstrapped before each test.

Then we added the ng2Injector to this module using a factory and a closure:

let ng2Injector: Injector = null;

angular.module(moduleName)
    .factory('ng2.Injector', function (): Injector {
        return ng2Injector;
    });

upgrade.bootstrap(document.body, [moduleName])
    .ready((ref: UpgradeAdapterRef) => {
        ng2Injector = ref.ng2Injector;
    });
@angular-automatic-lock-bot
Copy link

@angular-automatic-lock-bot angular-automatic-lock-bot bot commented Sep 8, 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.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 8, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants