-
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
Karma test breaks after using ui-router. #212
Comments
This has to do with the fact that the state machine fires off GET requests for templates, but in the test suite, all HTTP requests must be mocked out. The simplest solution would be to add @jeme, @ksperling Do we need some kind of integration with |
@nateabele what may be woth noting that @wpoosanguansit says it worked with the old router, which AFAIK makes the same GET request. So i expect he already knows that, so there must be some subtle difference. @wpoosanguansit Maybe if you could generate some example data for us to investigate, E.e. couple of plunkers or something. (one with angular own routing and one using ui-router) |
Interestingly, I can't seem to find anything in the |
Hi, I have been trying to put the code in plnkr.co but I still have no clue how to make it run with Karma test. I have posted the code at: http://plnkr.co/edit/KURAyKztD5a183YxRS1d?p=preview The error is raised when $digest is called: scope.$digest();
Thank you for your help. |
Hi, sorry for not being clear. I was actually looking for your |
Hi, I hope I understand it correctly. I only have this to handling routing: $stateProvider Is this the ngRoute? If there is a sample test case with services in the sample project, it would be much clearer to see how things are setup and what is needed to handle the promised produced by the service. At the moment, I only see the error with the call to $digest, which in my understanding, is needed to resolve the promised received. Thanks On Jul 1, 2013, at 11:42 PM, Nate Abele [email protected] wrote:
|
By |
I must have miscommunicate that I think. I only have the code snippet to handle the routing. And in the test, I did not reference any state at all. On Jul 2, 2013, at 12:21 AM, Nate Abele [email protected] wrote:
|
I was referring to this:
By which I took to mean that you were initially using Angular's built-in |
I see what you meant now. It was the demo app test created with yeoman that I started out testing angular. I then added hi-router to test and I ran the same test and got the error. But that was resolved when I changed the controller to be not abstract state. And I ran into the error again when I need to call $digest. As I mentioned earlier, I am not sure if that is related. I am sorry for the confusion. On Jul 2, 2013, at 8:37 AM, Nate Abele [email protected] wrote:
|
I also ran into this issue when I tried to test my ui-router based controllers with karma unit tests. For testing my controllers I implemented a simple $state mock which overrides the state transition (and thus template downloading) completely. The added benefit is that I can verify that correct transitions happen. Here is the mock snippet (untested): angular.module('stateMock',[]);
angular.module('stateMock').service("$state", function(){
this.expectedTransitions = [];
this.transitionTo = function(stateName){
if(this.expectedTransitions.length > 0){
var expectedState = this.expectedTransitions.shift();
if(expectedState !== stateName){
throw Error("Expected transition to state: " + expectedState + " but transitioned to " + stateName );
}
}else{
throw Error("No more transitions were expected!");
}
console.log("Mock transition to: " + stateName);
}
this.expectTransitionTo = function(stateName){
this.expectedTransitions.push(stateName);
}
this.ensureAllTransitionsHappened = function(){
if(this.expectedTransitions.length > 0){
throw Error("Not all transitions happened!");
}
}
}); My test then looks like: 'use strict';
describe('Controller: LoginCtrl', function () {
// load the controller's module
beforeEach(module('myApp'));
//load the mock module thus overriding the $state service
beforeEach(module('stateMock'));
var LoginCtrl,
scope,
state;
// Initialize the controller and a mock scope
beforeEach(inject(function ($controller,$state, $rootScope) {
scope = $rootScope.$new();
state = $state;
LoginCtrl = $controller('LoginCtrl', {
$scope: scope
});
}));
it('It should transition to mainScreen state if login is successful', function () {
state.expectTransitionTo("mainScreen");
//Other test logic goes here....
//At the end of the test
state.ensureAllTransitionsHappened();
});
}); In my case this is enough to test my ui-router based controllers. Maybe it will be useful to others as well. |
Hello, I'm just wondering what the status of this is? ui-router gets in the way of doing $httpBackend tests on services. Besides just the templateUrl stuff which is easy to pass through, if you do a resolve in a state provider that does an http call, then you're screwed.. I feel this is something that should be solved and packaged with ui-router. Thoughts? |
I just created a uiRouterNoop module that I inject in specific tests that I do not want the uiRouter to be triggered.. seems to work well. // uiRouterNoop.js helper module
mod = angular.module('uiRouterNoop', []);
mod.service('$state', function() { return {} });
mod.service('$urlRouter', function() { return {} });
// in a spec where $state and $urlRouter should be skipped -- ie. a http model
beforeEach(module('uiRouterNoop')); |
That seems pretty overly-simplistic, but if you have any suggestions, I'm all ears. |
Yea it's definitely too simplistic, but when testing just model code that only interacts with some backend then ui-router can be noop'ed. I'm actually not sure what the best thing to do is.. it's correct for ui-router to be executing that code, but I think having more control over when that code is run so someone can anticipate the calls and then test for them.. ie. generally, how would someone write tests for functions that are defined in the config of providers? .. it's definitely not easy to do On 2013-09-19, at 3:25 PM, Nate Abele [email protected] wrote:
|
Well, requests for templates and resolves shouldn't actually be fired until you call |
If you are testing a promise then to kick it off you need to call $digest or $apply, and this is when there can be issues. For me so far @Vratislav solution works to avoid the exceptions and has the added benefit of transition verification. |
Exactly as @jwall says, if you are mocking out promises then the necessary call to $digest triggers the unexpected template load. Personally I am happy to simply expect the call like so:
|
Yeah, there's definitely some stuff we could do to make testing more fluid, but it's hard to have a one-size-fits-all solution like mocking out template-handling, when some people might be writing integration tests that depend on templates loading. |
I updated the state mock from @Vratislav to support returning a promise (so you can test $state.go('state2').then()) and aliased $state.go to point to $state.transitionTo https://gist.github.com/wilsonwc/8358542 A question has also been answered on SO for this issue and how to implement the above gist: |
@wilsonwc Nice! I starred your gist and will see about integrating it into the main library. |
It is worth noticing that we don't get this However, as soon as the run loop is declared: Those errors are raised. Is there any plan to fix this rather than mocking each and every request to get those templates? |
@olivierpichon Yup, would love to. Not sure when it'll happen though. Let me know if you'd like to submit a pull request in the meantime. |
@olivierpichon Having same problem. Removing $state from my run blocks removes the test errors |
@rramsden, thanks mate! @nateabele I'd love to when I'll get to know the codebase better. |
Thanks a ton to @wilsonwc @Vratislav. After some wrangling I was able to figure this out, but definitely would have been lost if I didn't find this issue. @nateabele What are the odds that stateMock will get integrated into UI.Bootstrap, or better yet, Karma tests showcased in the sample app? I think it'd be a great resource for those of us new to TDD. |
same issue. pkieltyka's solution works. |
Those of you experiencing this issue, please add |
That does not seem to help in my case |
@danse when you run $digest(), what url is requested? Is it your app's default state's template? |
Initial StateWhen the
Tests involving state transitionsIf your unit tests involve ui-router transitions, UI-Router will attempt to fetch the templates required for the transition. You will need to either register each template fetch with the To register a template fetch with
To preload your templates, use a karma pre-loading tool such as the one @ghost linked in this comment: #212 (comment) If the templates are preloaded into the template cache by such a tool, $httpBackend is never invoked by UI-Router when it requests the template, and your state can be transitioned to in a test-friendly synchronous manner. To preload your templates manually, do something like the following:
Ionic UsersI've recently discovered that ionic preloads all UI-Router templates into Ionic's own template cache service. Disable that in your tests by either preloading, as mentioned above, or by disabling the $ionicTemplateCache service. To disable the $ionicTemplateCache service, set the maximum number of templates to
If that doesn't work, nuke the $ionicTemplateCache service by stubbing it out:
|
It's maybe because I'm a noob with unit tests but it still not working for me. I've tried adding the code @christopherthielen commented but I've the same error: I use ionic with the ui-router and when I put a $scope.digest() (for testing promises), I've this error even if I quit the $state of the controller (and I don't have any action with ui-router in the controller). In addition, with the promise I don't use $httpBackend nor other things (the service mocked with promise doesn't call an Api). The only thing it's working is when I add this in the inject function: But I would like to find a solution that works "automatically" without adding these lines in each unit tests controllers. Any idea? |
Let's try the following lines as they work for me (ionic v1.0.0-beta.14):
|
Thanks!!!! Finally it works! :D |
Seems a bit ridiculous that the Ionic team didn't even consider testing when writing that. Only the nuking method worked for me. |
Thanks - @christopherthielen - your Ionic section fixed up the issues I was having!!! |
@ghost, @christopherthielen thanks. That worked brilliantly! |
does the trick for me. Also, thanks for the explanation. It's good to know that |
Ionic + ng-describeWe're using When using This worked for us
This way |
@christopherthielen's solution does not work for me. The GET request keeps coming are met with 404 continuously until a 5 seconds timeout occurs:
|
While I am able to resolve the issue of GET requests via the nghtml2js preprocessor, I'm wondering, what is the best way to test state transitions? Is using the stateMock above the only way? The example code on this website this website shows the use of $state.go and $state.current in a test, but for me this does not work. $state.go seems to have no effect and the $rootScope.$digest() always loads the default state into $state.current. Code: // Test whether our state activates correctly
it('should activate the state', function() {
$state.go('state');
$rootScope.$digest();
expect($state.current.name).toBe('state');
}); |
Thanks a lot @Vratislav. You saved my day. |
Fixes the client-side tests after the removal of the <base/> tag from the main layout. These fixes aren't ideal. At the moment, they will suffice. This comment (angular-ui/ui-router#212 (comment)), among others in that issue, led me to choose this method as the fix to avoid having to change any other core code.
Hello everybody! I solved it using @jdart solution, but I'd like to implement @christopherthielen once since it's the one with more votes.
I get this error:
And when I try to inject $urlRouterProvider in my working beforeEach() block:
I get this other error:
Could you help me please? Thank you!! |
Hi,
It seems that few wrong commits has been made recently on KARMA/JASMINE, which are causing these issues, as mine old code base is working fine, only after installing fresh dependencies these test cases are failing now. I am using below dependencies -
Please help me out. |
Fixes the client-side tests after the removal of the <base/> tag from the main layout. These fixes aren't ideal. At the moment, they will suffice. This comment (angular-ui/ui-router#212 (comment)), among others in that issue, led me to choose this method as the fix to avoid having to change any other core code.
Hi,
I just tested out ui-router and ran my tests. It shows an error which didn't with normal router:
Error: Unexpected request: GET /views/templates/default-template.html
No more request expected
at Error ()
Is there anything special needed to be setup to work with Karma tests? Thanks for your help.
The text was updated successfully, but these errors were encountered: