Unit test an angular service (not factory) using Jasmine - angularjs

I've been trying to test an Angular service using Jasmine following tutorials, but for some reason their examples don't here works (they suggest injecting services using the angular.mock.inject() method)...
This is the way I got it working, but I am afraid this is not how it should be done...
Is this "good practice"? Why injecting doesn't work?
I basically import the service into the test, setup my module and $provide the service's dependencies, and new the service passing it what would normally be injected...
Anyway, here it is:
import rolesService from './roles.service.js';
describe('Roles', () => {
let RolesService;
let PermRoleStore;
let USER;
beforeEach(() => {
angular.mock.module('roles', ($provide) => {
$provide.constant('USER', {
roles: ['SOUTIEN_ORGANISME']
});
$provide.value('PermRoleStore', {
defineManyRoles: jasmine.createSpy(),
});
});
angular.mock.inject((_PermRoleStore_, _USER_) => {
PermRoleStore = _PermRoleStore_;
USER = _USER_;
RolesService = new rolesService(PermRoleStore, USER);
});
});
it('Setup should define the roles', () => {
RolesService.setup();
expect(PermRoleStore.defineManyRoles).toHaveBeenCalled();
});
describe('authorize', () => {
it('should return true if authorized', () => {
expect(RolesService.authorize('SOUTIEN_ORGANISME')).toBe(true);
});
it('should return false if the user it NOT authorized', () => {
expect(RolesService.authorize('NOT_AUTHORIZED')).toBe(false);
});
});
});
Here is the karma.config.js file just for reference:
'use strict';
const stringify = require('stringify');
const babelify = require('babelify');
module.exports = (config) => {
config.set({
basePath: '',
frameworks: ['browserify', 'jasmine-ajax', 'jasmine'],
files: [
{ pattern: 'build/gouvernementales/app-gouvernementales.config.json', watched: true, served: true, included: false },
'build/gouvernementales/js/gouvernementales-libs.js',
'src/apps/gouvernementales/app-gouvernementales.js',
'src/apps/gouvernementales/**/*.spec.js',
'src/modules/**/*.spec.js',
],
preprocessors: {
'src/apps/gouvernementales/app-gouvernementales.js': 'browserify',
'src/apps/gouvernementales/**/*.spec.js': 'browserify',
'src/modules/**/*.spec.js': 'browserify',
},
browsers: ['PhantomJS'],
plugins: [
'karma-phantomjs-launcher',
// 'karma-chrome-launcher',
'karma-jasmine-ajax',
'karma-jasmine',
'karma-browserify',
'karma-coverage',
'karma-mocha-reporter',
],
browserify: {
debug: true,
transform: [
babelify,
stringify,
],
},
helpers: [
'src/spec/helpers/**/*.js',
],
reporters: [
'mocha',
'coverage',
],
coverageReporter: {
dir: 'coverage/',
reporters: [
{ type: 'text-summary' },
{ type: 'html' },
],
},
logLevel: config.LOG_DEBUG,
singleRun: false,
colors: true,
autoWatch: true,
});
};

You don't need to do like this one
import rolesService from './roles.service.js'; // it should be not included.
//Should be injected
BEFOREEACH
beforeEach(() => {
angular.mock.module(($provide) => {
$provide.constant('USER', {
roles: ['SOUTIEN_ORGANISME']
});
$provide.value('PermRoleStore', {
defineManyRoles: jasmine.createSpy(),
});
});
//you are mocking PermRoleStore and USER,so should be inject it here.
//It will get available to your service
//no need of import
angular.mock.inject((_rolesService_) => {
PermRoleStore = _rolesService_;
});
});

Related

AngularJS Karma Jamsine Dependency Injection Error: Test Error: [$injector:unpr] Unknown provider: $mdDialogProvider <- $mdDialog

I'm trying to test a controller on an AngularJS app that injects $mdDialog as a dependency. I need to mock out the dialog but can't even get that far because the injection is not being recognized.
Here is the test file:
describe('responsesController', function() {
beforeEach(module('respondent.projects.project.responses'));
let responsesController, $rootScope, _$mdDialog_;
beforeEach(inject(function(_$controller_, _$rootScope_, _$mdDialog_,){
$rootScope = _$rootScope_
$scope = $rootScope.$new()
$mdDialog = _$mdDialog_
responsesController = _$controller_('responsesController', { $scope, $mdDialog })
}));
describe("First test" , function() {
it("Tests to see if tests are working", function() {
expect('test').toEqual('test');
});
});
});
But I am receiving this error:
Error: [$injector:unpr] Unknown provider: $mdDialogProvider <- $mdDialog
The module itself doesn't inject any dependencies:
export default angular
.module('respondent.projects.project.responses', [])
.controller('responsesController', responsesController)
....
However ngMaterial is injected in the main app module:
const app = angular.module('app', [
'ngMaterial',
...
]
Here is my karma.conf.js:
// Karma configuration
var webpackConfig = require('./webpack.config.js');
webpackConfig.entry = {};
var puppeteer = require('puppeteer');
process.env.CHROME_BIN = puppeteer.executablePath();
module.exports = function (config) {
config.set({
webpack: webpackConfig,
basePath: '',
plugins: [
'karma-chrome-launcher',
'karma-jasmine',
'karma-mocha-reporter',
'karma-babel-preprocessor',
'karma-webpack',
],
files: [
'node_modules/angular/angular.js',
'node_modules/angular-mocks/angular-mocks.js',
'apps/legacy/researcher/modules/projects/project/responses/module.js',
'apps/legacy/**/*.test.js',
],
exclude: [],
preprocessors: {
'apps/legacy/researcher/modules/projects/project/responses/module.js': ['webpack'],
'apps/legacy/**/*.test.js': ['babel'],
},
babelPreprocessor: {
options: {
presets: ['#babel/preset-env'],
sourceMap: 'inline',
},
},
reporters: ['mocha'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['ChromeHeadless'],
singleRun: false,
concurrency: Infinity,
});
};
What is the correct way to provide ngMaterial and/or $mdDialog to the controller for testing?

'Module is not available' when unit testing a component using typescript

Any ideas why the module is not found during the tests?
In karma.conf.js I've specified all the dependencies under the files property i.e angular, angular-mocks
But I have a feeling that app.component.ts and main.ts are not being compiled hence why they're not being found?
karma.conf.js
var webpackConfig = require('./webpack.test.config');
module.exports = function(config) {
'use strict';
var _config = {
basePath: '',
frameworks: ['jasmine', 'karma-typescript'],
files: [
'node_modules/angular/angular.js',
'node_modules/angular-mocks/angular-mocks.js',
'src/app/app.component.ts',
'src/main.ts',
{
pattern: 'src/app/**/*.+(ts|html)'
}
],
preprocessors: {
'**/*.ts': ['karma-typescript']
},
webpack: webpackConfig,
karmaTypescriptConfig: {
bundlerOptions: {
entrypoints: /\.spec\.ts$/
},
compilerOptions: {
lib: ['ES2015', 'DOM']
}
},
reporters: ['progress', 'karma-typescript'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: false,
browsers: ['Chrome'],
singleRun: true
};
config.set(_config);
};
webpack.test.config.js
var webpack = require('webpack');
var path = require('path');
module.exports = {
devtool: 'inline-source-map',
resolve: {
extensions: ['.ts', '.js']
},
module: {
rules: [{
test: /\.ts$/,
loaders: [{
loader: 'awesome-typescript-loader',
options: {
configFileName: path.join(__dirname, 'src', 'tsconfig.json')
}
}]
},
{
test: /\.html$/,
loader: 'html-loader'
}
]
}
};
app.component.spec.ts
import { AppComponent } from './app.component';
describe('Component: AppComponent', () => {
let Users;
beforeEach(function() {
angular.mock.module('myapp');
});
beforeEach(inject(function(_Users_: any) {
console.log(_Users_);
}));
});
app.component.ts
export class AppComponent implements ng.IComponentOptions {
static registeredName = 'dummy';
template: any;
constructor() {
this.template = require('./app.component.html');
}
}
main.ts
import { AppComponent } from "./app/app.component";
angular.module("myapp", ['pascalprecht.translate'])
.component(AppComponent.registeredName, new AppComponent())
.config(["$translateProvider", function($translateProvider: any) {
$translateProvider.determinePreferredLanguage();
}]);

Unit testing angular service with Karma in typescript : issue with inject

I have a very simple test where I inject $http $q and $httpBackend then do nothing (yet).
It crashs on the inject and I cannot figure out why.
Here's my code :
/// <reference path="../references.spec.ts" />
module Home.Test {
"use strict";
beforeEach(angular.mock.module("homeApp"));
describe("appInstanceService", () => {
let $httpBackend: angular.IHttpBackendService;
let $q: angular.IQService;
let service: Service.AppInstanceService;
beforeEach(
angular.mock.inject((
$http: angular.IHttpService,
_$q_: angular.IQService,
_$httpBackend_: angular.IHttpBackendService
) => {
$httpBackend = _$httpBackend_;
$q = _$q_;
service = new Service.AppInstanceService($http, $q, _, moment);
})
);
it("shoul pass", () => {
expect(true).toBe(true);
});
});
}
Here is my karma conf
module.exports = function(config) {
config.set({
// base path, that will be used to resolve files and exclude
basePath: '',
// testing framework to use (jasmine/mocha/qunit/...)
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
'./bower_components/angular/angular.js',
'./bower_components/angular-animate/angular-animate.min.js',
'./bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js',
'./bower_components/angular-mocks/angular-mocks.js',
'./bower_components/angular-sanitize/angular-sanitize.min.js',
'./bower_components/angular-translate/angular-translate.min.js',
'./bower_components/angular-ui-router/release/angular-ui-router.js',
'./bower_components/ui-select/dist/select.min.js',
'./bower_components/lucca-ui/dist/custom/lucca-ui-spe.js',
'./bower_components/moment/min/moment-with-locales.min.js',
'./bower_components/underscore/underscore-min.js',
'./dist/home.js',
'./tests/**/*.js',
],
preprocessors: {
'dist/home.js': ['coverage'],
},
// ngHtml2JsPreprocessor: {
// prependPrefix: '/web/Timmi.web/areas/timmi/'
// },
// list of files / patterns to exclude
exclude: [],
// web server port
port: 9876,
// level of logging
// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun: false,
plugins: [
'karma-jasmine',
// 'karma-chrome-launcher',
// 'karma-firefox-launcher',
// 'karma-ie-launcher',
'karma-phantomjs-launcher',
'karma-junit-reporter',
'karma-coverage',
// 'karma-ng-html2js-preprocessor'
],
browsers: ['PhantomJS'],
reporters: ['progress'],
junitReporter: {
outputFile: 'test-karma-results.xml',
suite: 'Lucca',
useBrowserName: false
},
coverageReporter: {
type : 'json',
dir : 'coverage/',
subdir: '.',
file : 'coverage-final.json'
}
});
};
And here is the error message I get in the console
Some bower_components were missing under the files section of my karma conf ...

angularjs requirejs karma directive templateUrl test fail

question
I replace templateUrl with template in author-signature.js, then I test success.
But I use templateUrl way in author-signature.js, I test fail. I watch files loading and chrome debug, author-signature.html did translate to js, and html content did exist in $templateCache too, but I test fail. Printscreen:
author-signature.html.js
$templateCache debug content
filepath
--public
----scripts
--------**/*.js
--test
----**/*.js
--views
----templates
--------**/*.html
test-main.js
require.js main entry file
var allTestFiles = [];
var TEST_REGEXP = /(\-test)\.js$/i;
Object.keys(window.__karma__.files).forEach(function (file) {
if (window.__karma__.files.hasOwnProperty(file)) {
if (TEST_REGEXP.test(file)) {
allTestFiles.push(file);
}
}
});
require.config({
baseUrl: '/base/public/scripts',
paths: {
'jquery': '../libs/jquery/dist/jquery',
'angular': '../libs/angular/angular',
'angularMocks': '../libs/angular-mocks/angular-mocks',
'templates': '../../views/templates'
},
shim: {
'angular': {
deps: ['jquery'],
exports: 'angular'
},
'angularMocks': {
deps: ['angular'],
exports: 'angular.mock'
},
'templates/default/author-signature.html': ['angular']
},
deps: allTestFiles,
callback: window.__karma__.start
});
karma.conf.js
karma configuration file, I translate js to html by ng-html2js
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', 'requirejs'],
files: [
{pattern: 'public/libs/jquery/dist/jquery.js', included: false},
{pattern: 'public/libs/angular/angular.js', included: false},
{pattern: 'public/libs/angular-mocks/angular-mocks.js', included: false},
{pattern: 'public/scripts/**/*.js', included: false},
{pattern: 'views/templates/**/*.html', included: false},
{pattern: 'test/**/*-test.js', included: false},
'test/test-main.js'
],
exclude: [
'public/scripts/build-main.js',
'public/scripts/require-config.js',
'public/scripts/bootstrap.js'
],
browsers: ['Chrome'],
reporters: ['progress', 'html', 'coverage'],
htmlReporter: {
outputFile: 'report/units.html',
pageTitle: 'Unit Tests',
subPageTitle: 'Unit tests with karma jasmine'
},
preprocessors: {
'public/scripts/**/*.js': ['coverage'],
'views/templates/**/*.html': ['ng-html2js']
},
coverageReporter: {
type: 'html',
dir: 'report/coverage/'
},
ngHtml2JsPreprocessor: {
stripPrefix: 'views/',
stripSuffix: '.html',
moduleName: 'templates'
}
});
}
author-signature-test.js
directive test file
define(['angularMocks', 'directives/default/author-signature', 'templates/default/author-signature.html'], function () {
describe('Unit: Hello Directive', function () {
var $compile, $rootScope;
beforeEach(function () {
module('angularApp');
module('templates');
inject(function (_$compile_, _$rootScope_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
});
});
it('should display the hello text properly', function () {
var elt = $compile('<author-signature author="Plus"></author-signature>')($rootScope);
expect(elt.text()).toEqual('Plus');
});
});
});
author-signature.js
simply directive file
define('directives/default/author-signature', [
'angular-app'
], function (angularApp) {
angularApp.directive('authorSignature', function () {
return {
restrict: 'EA',
scope: {
author: '#'
},
replace: true,
templateUrl: 'templates/default/author-signature'
};
});
});
author-signature.html
<h1>{{author}}</h1>
angular-app.js
define('angular-app', [
'angular'
], function (angular) {
var angularApp = angular.module('angularApp', []);
return angularApp;
});
OMG, I forget add $rootScope.$digest(); in test directive.
That cause this directive scope's attributes doesn't change.

jquery-jasmine unable to load json files

I've seen this question posted but can't seem to resolve the error. I'm trying to use jquery-jasmine to return some fake data and I'm unable to get past the 404 error when trying to load the json file. I'm using yeoman to scaffold my angular-gulp project. Is it not a good idea to put the json file in the module, along side the spec file? Where does karma run from, is this where I should be putting the json file? I tried using an absolute path for jasmine.getJSONFixtures().fixturesPath but still get an error. I added 'base' to the path of the fixture because I saw this fixed the error in another post but it didn't work for me. Any ideas?
WARN [web-server]: 404: /base/src/app/home/home.fixture.json?_=1445293824062
PhantomJS 1.9.8 (Mac OS X) homeController should have some resultsets FAILED
Error: JSONFixture could not be loaded: base/src/app/home/home.fixture.json (status: error, message: undefined)
undefined
project/
src/
app/home
home.controller.spec.js
home.fixture.json
...
gulp/unit-test.js
karma.conf.js
...
karma.conf.js:
'use strict';
module.exports = function(config) {
config.set({
basePath: '../',
autoWatch : true,
frameworks : ['jasmine'],
browsers : ['PhantomJS'],
plugins : [
'karma-phantomjs-launcher',
'karma-chrome-launcher',
'karma-firefox-launcher',
'karma-safari-launcher',
'karma-jasmine'
],
exclude : [
],
files : [
// fixtures
{
pattern: 'src/**/*.fixture.json',
watched: true,
served: true,
included: false
}
]
});
};
home.controller.spec.js
'use strict';
describe('homeController', function(){
beforeEach(function() {
module('homeModule');
var $httpBackend, scope, homeController, storageFactory;
module(function($provide) {
$provide.service('storageFactory', storageFactory);
});
inject(function($rootScope, $controller, $injector) {
$httpBackend = $injector.get('$httpBackend');
jasmine.getJSONFixtures().fixturesPath = 'base/src/app/home';
$httpBackend.whenGET('http://localhost:3000/my/api/home').respond(
getJSONFixture('home.fixture.json')
);
scope = $rootScope.$new();
homeController = $controller('homeController', {
$scope: scope
});
storageFactory = $injector.get('storageFactory');
});
});
it('should have some resultsets', function() {
$httpBackend.flush();
expect(scope.result_sets.length).toBe(59);
});
});
I had the same setup with yeoman-Angularjs-gulp and jquery-jasmine with the same 404 problem.
I solved it in 2 way,
The basePath was not setup in my karma config.
The path of the json file were not initially loaded by karma so they never got found.
So I added the line in the file loading:
{pattern: path.join(conf.paths.src, '/mockjson/*.json'),
watched: false,
included: false,
served: true}
This is the basic karma config that was built by yeoman with the 2 extra line:
var path = require('path');
var conf = require('./gulp/conf');
var _ = require('lodash');
var wiredep = require('wiredep');
function listFiles() {
var wiredepOptions = _.extend({}, conf.wiredep, {
dependencies: true,
devDependencies: true
});
return wiredep(wiredepOptions).js
.concat([
path.join(conf.paths.src, '/app/**/*.module.js'),
path.join(conf.paths.src, '/app/**/*.js'),
path.join(conf.paths.src, '/**/*.spec.js'),
path.join(conf.paths.src, '/**/*.mock.js'),
path.join(conf.paths.src, '/**/*.html'),
{pattern: path.join(conf.paths.src, '/mockjson/*.json'), watched: false, included: false, served: true}
]);
}
module.exports = function (config) {
var configuration = {
files: listFiles(),
singleRun: true,
autoWatch: false,
basePath: '',
frameworks: ['jasmine', 'angular-filesort'],
angularFilesort: {
whitelist: [path.join(conf.paths.src, '/**/!(*.html|*.spec|*.mock).js')]
},
ngHtml2JsPreprocessor: {
stripPrefix: 'src/',
moduleName: 'pagesBehindCouch'
},
browsers: ['PhantomJS'],
plugins: [
'karma-phantomjs-launcher',
'karma-angular-filesort',
'karma-jasmine',
'karma-ng-html2js-preprocessor'
],
preprocessors: {
'src/**/*.html': ['ng-html2js']
}
};
config.set(configuration);
};
I think the pattern: 'src/**/*.fixture.json', might be not at the src location you think it is.
Exemple that really helped me: Gunnar Hillert's Blog
In my case, I was loading an environment-configuration.json file in order to bootstrap the AngularJS application.
So, I also had to specify the proxy settings.
proxies: {
'/mockjson/': '/base/src/mockjson/',
}

Resources