Angular + Jasmine Testing - javascript

I'm very new, (a total newb) to both AngularJS and BDD testing with Jasmine. My goal for this weekend is to become a little more competent with both.
I'm currently following the tutorial that's available on the angularJS site and I'm working on the files locally. In Chapter 2 it briefly touches on creating Angular tests with Jasmine.
However, I've done exactly as the tutorial states and Jasmine is failing. The test is simply to ensure that exactly 3 phones are rendered in the HTML. (which there are).
Here's the test:
describe('PhoneListCtrl', function() {
it('should create "phones" model with 3 phones', function() {
var scope = {},
ctrl = new PhoneListCtrl(scope);
expect(scope.phones.length).toBe(3);
});
});
The error that I'm getting on my tests.html page is:
ReferenceError: PhoneListCtrl is not defined
Here's tests.html:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Jasmine Spec Runner v2.0.0</title>
<link rel="shortcut icon" type="image/png" href="jasmine/jasmine_favicon.png">
<link rel="stylesheet" type="text/css" href="jasmine/jasmine.css">
<script type="text/javascript" src="jasmine/jasmine.js"></script>
<script type="text/javascript" src="jasmine/jasmine-html.js"></script>
<script type="text/javascript" src="jasmine/boot.js"></script>
<!-- include source files here... -->
<script src="js/controllers.js"></script>
<!-- include spec files here... -->
<script type="text/javascript" src="spec/spec.js"></script>
</head>
<body>
</body>
</html>
I know there's nothing wrong with js/controllers.js because 3 phones are being rendered (by Angular) in my index.html page so I've definitely gone wrong somewhere with setting up Jasmine but not entirely sure where...
Update:
PhoneListCtrl is defined as follows:
var phonecatApp = angular.module('phonecatApp', []);
phonecatApp.controller('PhoneListCtrl', function ($scope) { .. });
I have also tried the following:
describe('PhoneListCtrl', function(){
beforeEach(module('phonecatApp'));
it('should create "phones" model with 3 phones', inject(function($controller) {
var scope = {},
ctrl = $controller('PhoneListCtrl', {$scope:scope});
expect(scope.phones.length).toBe(3);
}));
});
but with the above I get 'module' is not defined...

The tutorial project Angular-phonecat is based on angular-seed which uses karma test runner to run jasmine tests.
All the JS files should be included on karma config file test/karma.conf.js. See the example from angular-phonecat sources. The line that will include the PhoneListCtrl is:
'app/js/**/*.js'
Tests can be run using npm test which equals to karma start test/karma.conf.js (the command is configured on package.json file)
If you have cloned the angular-phonecat project like instructed on the tutorial main page, you should already have working karma config file.

Related

How do you run mocha tests in the browser?

Is it just me, or does their documentation not explain how to run the tests in the browser at all?
Do I have to create that HTML file that they show in the example? How do I make it run my specific set of test cases for my project then?
I want the same output as running mocha from project root. All subdirectories inside the test folder need to be included
If we need to run our tests in a browser, we need to set up a simple HTML page to be our test runner page. The page loads Mocha, the testing libraries and our actual test files. To run the tests, we’ll simply open the runner in a browser.
example html code :
<!DOCTYPE html>
<html>
<head>
<title>Mocha Tests</title>
<link rel="stylesheet" href="node_modules/mocha/mocha.css">
</head>
<body>
<div id="mocha"></div>
<script src="node_modules/mocha/mocha.js"></script>
<script src="node_modules/chai/chai.js"></script>
<script>mocha.setup('bdd')</script>
<!-- load code you want to test here -->
<!-- load your test files here -->
<script>
mocha.run();
</script>
</body>
</html>
Setting up a Directory Structure
You should put your tests in a separate directory from your main code files. This makes it easier to structure them, for example if you want to add other types of tests in the future (such as integration tests or functional tests).
The most popular practice with JavaScript code is to have a directory called test/ in your project’s root directory. Then, each test file is placed under test/someModuleTest.js.
Important things :
We load Mocha’s CSS styles to give our test results nice formatting.
We create a div with the ID mocha. This is where the test results are
inserted.
We load Mocha and Chai. They are located in subfolders of the
node_modules folder since we installed them via npm.
By calling mocha.setup, we make Mocha’s testing helpers available.
Then, we load the code we want to test and the test files. We don’t
have anything here just yet.
Last, we call mocha.run to run the tests. Make sure you call this
after loading the source and test files
I thought the documentation wasn't entirely clear too, but I figured it out eventually and got it set up. Here's how:
Include the Mocha script and CSS in Index.html. Also include a div with id "Mocha" for the output to be inserted into. Include the test script you'd like to execute.
<link href="lib/mocha/mocha.css" rel="stylesheet" />
<script src="lib/mocha/mocha.js"></script>
<script src="test/my_mocha_test.js"></script>
<div id="mocha"></div>
In your test file (my_mocha_test.js in this example) include this setup line at the top:
// 'bdd' stands for "behavior driven development"
mocha.setup('bdd');
Now with the test and the Mocha content all loaded, you can run the tests with this command:
mocha.run();
You can add that to an event listener and trigger it on a button push or other event, or you can just run it from the console, but it should put the test output in the div with the "mocha" id. Here's a page with all this set up with code viewable on GitHub for you to
https://captainstack.github.io/public-stackhouse/
My way to do it with:
ES6, import, export, chai
Used mocha 6.1.4 and chai 4.2.0.
src/MyClass.js:
export default class MyClass { }
test/MyClass.js:
import MyClass from "../src/MyClass.js";
let assert = chai.assert;
describe('MyClass tests', function () {
describe('The class', function () {
it('can be instantiated', function () {
assert.isObject(new MyClass());
});
});
});
test/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Mocha</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="mocha.css">
<script src="mocha.js"></script>
<script src="../node_modules/chai/chai.js"></script>
<script type="module" class="mocha-init">
mocha.setup('bdd');
</script>
<!-- ------------------------------------ -->
<script type="module" src="test.js"></script>
<!-- ------------------------------------ -->
<script type="module">
mocha.run();
</script>
</head>
<body>
<div id="mocha"></div>
</body>
</html>
The mocha.js and mocha.css files were created via mocha init test, but can also be found in node_modules/mocha.
If this is improvable, let me know. The answer is insprired by this post.
Here's the most basic chai/mocha test in the browser.
mocha.setup('bdd');
describe('test', () => {
it('passes', () => {
chai.expect(1).to.eql(1);
});
it('fails', () => {
chai.expect(1).to.eql(2);
});
});
mocha.run();
<div id="mocha" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/8.0.1/mocha.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/4.2.0/chai.min.js"></script>

Simple AngularJS 1.5.9 Component Not Rendering in MVC 5

I am trying to get AngularJS 1.5.9 up and running an MVC 5 application using a very simple component called configuration-list.
I created an MVC 5 application (4.5.2), added the Angular.Core 1.5.9 Nuget package
To take MVC 5, layout and razor rendering out of the picture, I created a simple file called test.htm:
<!DOCTYPE html>
<html ng-app>
<head>
<title></title>
<meta charset="utf-8" />
<script src="Scripts/angular.js"></script>
<script src="Scripts/app/module.js"></script>
</head>
<body>
<configuration-list></configuration-list>
</body>
</html>
And in module.js:
(function () {
"use strict";
angular.module("radar", []).component("configuration-list", {
template: "Hello from configuration list"
});
}());
The browser (IE 11) comes up empty.
I have opened the debugging tools and go to the console tab, and there are no errors logged.
I have put a breakpoint in module.js and it is hit (so I know the code is running)
I have tried moving the scripts below the component in the body tag
I have tried setting ng-app="radar" in the html tag
Any idea what I'm missing?
For components the naming has to be camelcase, not hyphencase
angular.module("radar", []).component("configurationList", {
template: "Hello from configuration list"
});

AngularUI Router + Ionic - routing works in browser, but not within Ionic View?

I have the most simple little Ionic App that works as expected when run in the browser using ionic serve.
However, when the app is run in Ionic View (view.ionic.io), the routing appears to be failing (the index.html is loaded, but nothing within <div ui-view=""></div> is loaded. This is done using ionic upload.
My simple index.html looks like:
<body ng-app="app">
my app!
<div ui-view=""></div>
</body>
My app.js contains:
angular
.module("app", [
"ionic",
"ngCordova",
"ui.router"
])
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider.state("splash", {
url: "/splash",
templateUrl: "components/splash/splash.html",
controller: "SplashController"
}).state("login", {
url: "/login",
templateUrl: "components/login/login.html",
controller: "LoginController"
});
$urlRouterProvider.otherwise("/splash");
});
I have a SplashController that has:
var SplashController = (function () {
function SplashController($scope) {
this.test = null;
this.scope = null;
$scope.vm = this;
this.scope = $scope;
this.test = "Hello world!";
}
SplashController.$inject = ["$scope"];
return SplashController;
})();
App.SplashController = SplashController;
angular.module("app").controller("SplashController", App.SplashController);
And my really boring splash.html is:
<div class="padding">
<h4 class="title dark">splash.html</h4>
<h4 class="title dark">{{ vm.test }}</h4>
</div>
In my browser (ionic serve) I see:
And on my device (ionic upload / Ionic View app) I just see my app!
What am I doing wrong? Is this an issue with the Ionic View app? Has anyone else run into this?
A few other things to note:
The JavaScript is compiled from TypeScript.
I had attempted <ion-nav-view></ion-nav-view> / excluding ui.router and the results were the same (works in the browser, but not on the device). I actually dislike the Ionic view animations and prefer to use the standard ui-router, if I can.
Well this turned out to be the strangest of issues. After further debugging, I realized that not only was the router not working, but Angular was not working at all ({{ 1 + 1 }}) displayed literally.
For some reason, the native app did not like my generated JavaScript in a .tsout directory. I removed it and placed the same exact file in the same directory as my index.html. I'm sure something else was going on behind the scenes, but re-structuring my project files seemed to solve the problem.
The setup with the error:
Project structure:
/www
/.tsout
app.js // both .tsout and app.js are created through my gulp-typescript task
/components
/css
/img
/lib
/typings
index.html
HTML head:
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title></title>
<link href="css/ionic.app.min.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<script src="lib/ionic/js/ionic.bundle.js"></script>
<script src="lib/ionic/js/ng-cordova.min.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
<script src=".tsout/app.js"></script>
</head>
The solution:
My project structure after I found success both in the browser and on the device:
/www
/components
/css
/img
/lib
/typings
index.html
app.js // just app.js is created through my gulp-typescript task
The script tag in the head then looks like:
<script src="app.js"></script>
Hope the outcome of this wonkiness can be helpful to someone else!

Properly use custom angularjs service, function not defined error

I created my own service for some util methods. The idea was to simply inject the utilsservice into the modules where I need the methods. The Problem is I get an ReferrenceError: myFunction is not defined.
I think it has to do with the wrong injecting of the service, but i can't figute out myself what's wrong with my approach.
The service i made:
angular.module('utils',[]).service('UtilsService',function(){
this.myFunction = function(){};
});
In my app.js file i have following structure:
(function(){
angular.module('utils',[]);
angular.module('translation',[]);
var app = angular.module('myApp',['translation','utils']);
app.controller('myController',['$http',function($http,UtilsService){
UtilsService.myFunction();
}]);
});
The order I included the scripts in my .html file:
<script type="text/javascript" src="../Libraries/angular.min.js"></script>
<script type="text/javascript" src="../js/angular-js/services/utilService.js"></script>
<script type="text/javascript" src="../js/angular-js/app.js"></script>
<script type="text/javascript" src="../js/angular-js/translate.js"></script>
I already tried to change the order but it doesn't make any difference.
I am thankfull for any advice you may have!
Please try the below. You will need to change the script references to point to the files where you have them. Once the index.html file has loaded, you should see the output "you called myFunction()" in the console window. That is being printed from within the service which shows it's being called correctly. I've also created a fiddle
index.html:
<!doctype html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="UTF-8">
<title>Directives</title>
</head>
<body>
<div ng-controller="myController"></div>
<script src="angular.js"></script>
<script src="app.js"></script>
<script src="utilsService.js"></script>
</body>
</html>
app.js (I have moved the code out of the function you created since it wasn't working. Also, you had a typo for spelling anguar on the line that begins with var app. I have also removed the dependency for translation in my code since I didn't create any module by that name):
(function(){
//angular.module('utils',[]);
//angular.module('translation',[]);
});
var app = angular.module('myApp',['utils']);
app.controller('myController',['$scope', 'UtilsService',function($scope,UtilsService){
UtilsService.myFunction();
}]);
utilsService.js:
angular.module('utils',[])
.service('UtilsService',function(){
this.myFunction = function(){ console.log ('you called myFunction()')};
});

coffeescript: suppress "ReferenceError"

Currently working through this tutorial on using Backbone.js with coffeescript.
Leveraging the following index.html file:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>CoffeeScript, Meet Backbone.js: Part N</title>
<link rel="stylesheet" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<script src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
<script src="http://ajax.cdnjs.com/ajax/libs/underscore.js/1.1.6/underscore-min.js"></script>
<script src="http://ajax.cdnjs.com/ajax/libs/backbone.js/0.3.3/backbone-min.js"></script>
<script type="text/javascript" src="./index.js"></script>
</head>
<body>
<header>
<h1>CoffeeScript, Meet Backbone.js: Part 1</h1>
</header>
</body>
</html>
which loads an index.js file after loading Backbone, jQuery, etc from a cdn. Hoping to work within a script.coffee file that I'd like to have automatically compile into the script.js file loaded by index.html above by running something like coffee script.coffee -c -w.
Trouble is, I'm getting ReferenceErrors when I try to run the above command on the following script.coffee file:
jQuery ->
class ListView extends Backbone.View
el: $ 'body'
initialize: ->
_.bindAll #
#render()
render: ->
$(#el).append '<ul><li>Hello, Backbone!</li></ul>'
list_view = new ListView
For instance:
ReferenceError: jQuery is not defined
...
because, clearly, jQuery is being loaded in the index.html file.
Is there a way to suppress the error reporting from the coffeescript compiler so that it just converts the code without the error?
The options must go before the file, e.g.:
coffee -cw script.coffee
Otherwise, it will try to run script.coffee right then and there as a Node.js script, passing it the options -c and -w. That's not what you want; if you want the CoffeeScript compiler to get the options, it's got to be before the file name.

Categories