You're using ui-router to manage Angular 1.x routing states.
You have a parent state that should always navigate to a child state, but without relying on ui-router-extras like $deepStateRedirect. This is to avoid deep linking into the child state. Some logins need to operate this way, for instance, so the Terms of Service acknowledgement cannot be skipped.
This is an example ui-router state hierarchy that defines a series of states used for login pages.
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'app/login/login.html',
controller: 'LoginController',
controllerAs: 'loginVm'
})
.state('login.tos', {
templateUrl: 'app/login/tos.html',
controller: 'TosController',
controllerAs: 'tosVm'
})
.state('login.credentials', {
templateUrl: 'app/login/credentials.html',
controller: 'credentialsController',
controllerAs: 'credVm'
});
Note the lack of urls for the child states. This prevents directly navigating to any child state.
Also note that $deepStateRedirect (part of ui-router-extras would allow a configuration like the following to automatically navigate from the parent login state to the child login.tos state,
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'app/login/login.html',
controller: 'LoginController',
controllerAs: 'loginVm',
deepStateRedirect: {
default: {
state: 'login.tos'
}
}
})
...
The problem with using $deepStateRedirect in this case is it also allows a browser refresh, for instance, to remain in any child state like login.credentials, which may not be desirable. (The same might be true of any sequential wizard, where navigating away and then back to the wizard should always start at the beginning.)
Without $deepStateRedirect, therefore, it is expected that the LoginController will be responsible for issuing $state.go('login.tos'); whenever the login state is activated.
In order to test such a controller-mitigated state transition, the LoginController must be instantiated by ui-router during testing. The following test harness involves compiling a simple HTML snippet that provides the <div ui-view /> tag required by ui-router. (Inspired by ui-router unit tests)
it('should chain from the parent state to the proper child state', function() {
$httpBackend.when('GET', function() {return true;}).respond(200);
$compile('<div> <div ui-view/> </div>')($rootScope);
$state.go('login');
$rootScope.$digest();
expect($state.is('login.terms')).to.be.true;
};
Note the use of $httpBackend to mock responses to any request the LoginController may make. If your controller doesn't make such requests, this mock isn't necessary.