I work on an app based on Angular 1.5, angular-ui-router and WebPack for which I want to make unit tests on module declaration part, especially on state configuration (I want to test source code of resolve part).
All others unit tests of my app are working fine but on this one it looks like my call $state.go are never processed:
describe('Simple Module', () => {
beforeEach(angular.mock.module('ui.router', 'my-app'));
let $state;
let $location;
let $httpBackend;
beforeEach(inject((_$location_, _$state_, _$httpBackend_) => {
$state = _$state_;
$location = _$location_;
$httpBackend = _$httpBackend_;
}));
describe('app.onlineListing.error', () => {
it('go to state', () => {
const state = 'app.onlineListing.error';
$state.go(state);
// PROBLEM IS HERE...
// $state.current.name is empty ('') just like if $state.go was never called
// It's not better with $location.url and $httpBackend.flush
// ...
expect($state.current.name).toBe(state);
// I will spy on myService and expect that myService.getData has been called
// but currently state is not reach so resolve parts are never triggered...
});
});
});
Here is my app module:
export default angular.module('my-app', ['oc.lazyLoad', 'ui.router', mySimpleModule.name])
.config(($stateProvider, ...) => {
...
$stateProvider
.state('app', {
abstract: true,
...
}
});
There is mySimpleModule declaration:
export default angular.module('my-simple-module', [
'ui.router'
])
.config(($stateProvider) => {
$stateProvider
.state('app.onlineListing', {
url: '/onlineListing',
abstract: true,
views: {
body: {
template: '<ui-view />'
}
}
})
.state('app.onlineListing.error', {
url: '/error',
template: require('./configurationError/configurationError.html'),
controller: 'onlineListingConfigurationErrorCtrl',
controllerAs: 'controller',
resolve: {
// #ngInject
modules: ($q, $ocLazyLoad) => {
return $q((resolve) => {
require(['./configurationError/configurationError.js'], (module) => {
resolve($ocLazyLoad.load({ name: module.default }));
});
});
},
fetchedData: (myService) => {
// Finally I want my test to check if getData is called
return myService.getData();
}
}
})
});
Edit
I also try this tutorial (which is exactly what I try to achieve) but it's not working better.
Related
I am a newbie of AngularJS using version 1.6.4, What i am trying to do is redirect user on previous page with a complete refresh. Right now i am getting back but page is not refreshing. Any idea how can i do that with a single line code.
user-login.component.js:
(function () {
"use strict";
var module = angular.module(__appName);
function controller(authService, $window, $location, $document) {
var model = this;
model.$onInit = function () {
//TODO:
};
model.login = function () {
authService.login(model.email, model.password).then(function (response) {
//$window.history.back();
//$window.history.go(-1);
//$window.location.href = '/';
console.log("url:"+$document.referrer);
//$document.referrer is showing undefined in console
$location.replace($document.referrer);
},
function (response) {
model.msg = response.error;
});
}
}
module.component("userLogin", {
templateUrl: "components/user-login/user-login.template.html",
bindings: {
email: "<",
password: "<"
},
controllerAs: "model",
controller: ["authService", "$window", "$location", "$document" controller]
});
}());
App.js:
"use strict";
//Global variables
var __apiRoot = "http://localhost:8000/api"; //No slash '/' at the end
var module = angular.module(__appName, [
"ui.router",
"angular-jwt"
]);
module.config(function ($stateProvider, $urlRouterProvider, $httpProvider, jwtOptionsProvider) {
$urlRouterProvider.otherwise('/app/home');
$stateProvider
.state("app", {
abstract: true,
url: "/app",
component: "appRouting"
})
.state("app.home", {
url: "/home",
component: "homeRouting"
})
.state("app.search", {
url: "/search/:q",
component: "searchRouting"
});
jwtOptionsProvider.config({
tokenGetter: ['authService', function (authService) {
return authService.getToken();
}],
whiteListedDomains: ['localhost']
});
$httpProvider.interceptors.push('jwtInterceptor');
});
If you are using angular-ui-router and have name of previous state then use :
$state.go('previousState', {}, { reload: true });
If you don't have the name of the previous state then you could use this piece of code it will run every time state change will occur.
$rootScope.previousState;
$rootScope.currentState;
$rootScope.$on('$stateChangeSuccess', function(ev, to, toParams, from,fromParams) {
$rootScope.previousState = from.name;
$rootScope.currentState = to.name;
console.log('Previous state:'+$rootScope.previousState)
console.log('Current state:'+$rootScope.currentState)
});
you can refresh page by simply using native javascript. window.location.reload()
use $location.replace(). You can get the previous URL of where you came from using $document.referrer. $location.replace($document.referrer)
I built web app with angular1 and webpack2.
I want to make modal popup with own state so I used ui.router and
ui.bootstrap.
But the problem is, onEnter method doesn't work.
below is my app.js,
and I brought codes about modal at here :
Open Modal and change URL without change the view in AngularJS
import angular from 'angular';
import 'angular-ui-router';
import 'angular-ui-bootstrap';
import 'angular-resource';
// controllers
import homeController from './pages/home/home-controller';
import playerController from './pages/player/player-controller';
import toolbarController from './components/toolbar-controller';
angular.module('907dg', [
'ui.router',
'ui.bootstrap'
])
.config(($stateProvider, $locationProvider) => {
$stateProvider
.state('home', {
url: '/',
template: require('./pages/home/home.html'),
controller: 'HomeController'
})
// modal codes
.state('player', {
url: '/player/:playerName',
onEnter: function($stateParams, $state, $modal) {
console.log('here is player modal');
$modal.open({
template: '<div><h1>PLAYER MODAL POPUP</h1></div>',
resolve: {},
controller: function($scope, $state) {
$scope.ok = function () {
$scope.$close();
};
$scope.dismiss = function () {
$scope.$dismiss();
};
}
}).result.then(function (result) {
// $scope.$close
}, function (result) {
// $scope.$dismiss
}).finally(function () {
// finally
return $state.transitionTo('home');
});
}
});
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
})
.controller('MasterController', ($scope) => {
$scope.greeting = 'HERE IS INDEX';
})
.filter('trustAsResourceUrl', ['$sce', function($sce) {
return function(val) {
return $sce.trustAsResourceUrl(val);
};
}]);
playerController();
homeController();
toolbarController();
and the controller that calls modal.
$scope.show = function (pName) {
$state.go('player', { playerName: pName });
};
i start working with angular 1.x boilerplate and have 1 problem, i can`t send into resolver promise from service
function ExampleService($http) {
'ngInject';
const service = {};
let getTasks = ()=> {
return $http.get('tasks');
};
service.isReady = new Promise((resolve, reject)=> {
getTasks().then(
(data) => {
resolve(data);
},
(err, status) => {
reject(err, status);
});
});
return service;
}
export default {
name: 'ExampleService',
fn: ExampleService
};
But when i try inject ,y service to on_config.js i have error
Uncaught Error: [$injector:modulerr] Failed to instantiate module app due to:
Error: [$injector:unpr] Unknown provider: ExampleService
My stateProvider
$stateProvider
.state('Home', {
url: '/',
controller: 'ExampleCtrl as home',
templateUrl: 'home.html',
title: 'Home',
resolve:{example:ExampleService.isReady}
})
Maybe i do something wrong or you can suggest how can i impelemt logic for preloading some data to app before rendering first controller
P.S. link to bolerplate
Services can't be injected into config blocks. They need to be injected in resolver functions:
$stateProvider
.state('Home', {
url: '/',
controller: 'ExampleCtrl as home',
templateUrl: 'home.html',
title: 'Home',
resolve:{
example: function (ExampleService) {
return ExampleService.isReady();
}
})
Also the isReady needs to be a function, not a new promise:
service.isReady = () => {
return getTasks().then(response => response.data);
}
I have an app that uses angular. In the app.config is where I have to setup my routes, however I want to authorize my routes because not everyone who uses the app can see every page.
So I have already tried to make a factory that gives a boolean to tell the app if that person can see the route or not, and learned that I cannot inject a factory into a config.
So I have made a provider that I can inject into the config:
(function () {
'use strict';
angular.module('services')
.factory('Auth', ['$http', function AuthFactory($http) {
return {
LinkAuth: function (Name) {
return $http({ method: 'GET', url: '/Dashboard/AuthorizeNavItem', data: { Name: Name } });
}
}
}]);
angular.module('services')
.provider('AuthProvider', ['Auth', function (Auth) {
var allowed = false;
this.$get = function (Name) {
Auth.LinkAuth(Name).success(function (data) {
allowed = data.Authorized;
});
return allowed;
}
}]);
})();
My app.config:
(function () {
'use strict';
angular.module('app.it', [])
.config(['$stateProvider', 'msNavigationServiceProvider', 'AuthProvider', function ($stateProvider, msNavigationServiceProvider, AuthProvider) {
$stateProvider
.state('app.it', {
abstract: true,
url: '/information-technology',
})
.state('app.it.users', {
url: '/users',
views: {
'content#app': {
templateUrl: '/IT/Users',
controller: 'ITUserController as vm'
}
}
});
/*
We need to get a bool to say if a user is part of a group that can see this page.
*/
var allowed = true;//I want the provider $get method to return that bool here
if (allowed)
{
//This builds the navigation bar
msNavigationServiceProvider.saveItem('app.authroute', {
title: 'Authorized Route',
icon: 'icon-monitor',
weight: 2
});
//This builds the navigation bar
msNavigationServiceProvider.saveItem('app.authroute.route', {
title: 'Route',
state: 'app.authroute.route'
});
}
}]);
})();
How do I access that AuthProvider $get and store the bool in a variable in the config?
following is the code from my sample angular project.
app.js code:
(function () {
'use strict';
var app = angular.module('actorsDetails', [
// Angular modules
'ngResource',
// 3rd Party Modules
'ui.bootstrap',
'ui.router'
]);
app.config(['$stateProvider', '$urlRouterProvider', configRoutes]);
function configRoutes($stateProvider, $urlRouterProvider) {
$stateProvider
.state('main', {
url: '/main',
templateUrl: 'app/home/home.html',
controller: 'HomeCtrl',
controllerAs: 'vm'
})
.state('form', {
url: '/form',
templateUrl: 'app/form/form.html',
controller: 'FormCtrl',
controllerAs: 'vm',
resolve: {
initialData: ['actorApi', function (actorApi) {
return actorApi.getActorsResource();
}]
}
})
.state('resource', {
url: '/resource',
templateUrl: 'app/resource/resource.html',
controller: 'ResourceCtrl',
controllerAs: 'vm',
resolve: {
initialData: ['actorApi', function (actorApi) {
return actorApi.getActorsResource();
}]
}
});
$urlRouterProvider.otherwise('/main');
}
app.run(['$state', function ($state) {
// Include $route to kick start the router.
}]);
})();
controller code:
(function () {
'use strict';
angular.module('actorsDetails').controller('HomeCtrl', HomeCtrl);
/* #ngInject */
function HomeCtrl($state) {
/* jshint validthis: true */
var vm = this;
vm.activate = activate;
vm.test = true;
vm.navigate = navigate;
activate();
function activate() {
}
function navigate() {
$state.go('form');
}
}
})();
**test.js**
describe('HomeCtrl', function() {
beforeEach(module('actorsDetails'));
beforeEach(inject(function ($rootScope, $controller) {
var scope = $rootScope.$new();
var HomeCtrl = $controller('HomeCtrl', {
$scope: scope
});
}));
it('should have a HomeCtrl controller', function() {
expect(true).toBeDefined();
});
});
there are the files I have included in my karma.config.js
I have added all the angularJS dependent files.
I have also added the controller file that i need to test
files: [
'src/lib/angular/angular.min.js',
'src/lib/angular-mocks/angular-mocks.js',
'src/lib/angular-resource/angular-resource.min.js',
'src/lib/angular-route/angular-route.min.js',
'src/app/app.js',
'src/app/home/home.controller.js',
'src/test/specs/*.js'
],
kindly pinpoint me, what is that I am doing wrong...
Mock out the $state object in your unit test.
var mockState = { go: function() {} };
var HomeCtrl = $controller('HomeCtrl', { $scope: scope, $state: mockState });
The $injector:modulerr is most likely related to your use of $state in your controller. Instead of mocking, you could try adding the library to your karma config, and loading the module in your unit test.
'src/lib/angular-ui-router/release/angular-ui-router.min.js'
beforeEach(module('ui.router'));